import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
// import 'package:flutter_screenutil/flutter_screenutil.dart'; // 未使用
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:gal/gal.dart';
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
import 'package:flutter_sound/flutter_sound.dart';

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import '../../../data/services/channel_service.dart';
import '../../../data/services/video_service.dart';
import '../../../data/services/playback_service.dart';
import '../../../data/services/record_service.dart';
import '../../../data/services/alarm_service.dart';
import '../../../data/services/user_service.dart';
import '../../../data/services/download_database_service.dart';
import '../widgets/record_data_manager.dart';
import '../../download/controllers/download_controller.dart';
import '../../../data/models/download_record.dart';
import '../../message/controllers/message_controller.dart';
import '../../home/controllers/home_controller.dart';

class DeviceDetailController extends GetxController
    with WidgetsBindingObserver {
  // 服务实例 - GetX规范
  final ChannelService _channelService = Get.find<ChannelService>();
  final VideoService _videoService = Get.find<VideoService>();
  final PlaybackService _playbackService = Get.find<PlaybackService>();
  final RecordService _recordService = Get.find<RecordService>();
  final AlarmService _alarmService = Get.find<AlarmService>();

  // 视频播放控制器
  VideoPlayerController? _videoController;
  VideoPlayerController? get videoController => _videoController;

  // 当前选中的tab索引
  final currentTabIndex = 0.obs;

  // 视频相关状态
  final isVideoInitialized = false.obs;
  final isLoading = false.obs;
  final isPlaying = false.obs;
  final isMuted = false.obs;
  final wasMutedBeforeTalk = false.obs; // 对话前的音量状态
  final isFullscreen = false.obs;
  final isBuffering = false.obs; // 添加缓冲状态
  final videoErrorMessage = ''.obs; // 添加视频错误信息
  final playbackSpeed = 1.0.obs; // 播放速度（0.5x, 1x, 2x, 3x, 4x）
  final showPlayPauseButton = true.obs; // 控制暂停/播放按钮的显示

  // 流类型相关状态
  final currentStreamType = ''.obs; // 当前流类型：由后台SteamType决定
  final availableStreamTypes = <String>[].obs; // 可用的流类型列表
  final isStreamTypeDropdownOpen = false.obs; // 流类型下拉菜单状态

  // 设备信息
  final _deviceId = ''.obs;
  final _channelId = ''.obs;
  final _hsId = ''.obs;
  final deviceName = '设备加载中...'.obs;

  // 通道详情数据
  final channelDetail = Rxn<Map<String, dynamic>>();

  // 通道状态：ON 在线，OFF 离线
  final channelStatus = ''.obs;

  // 视频流相关
  final _streamUrl = ''.obs;
  final _streamId = ''.obs;
  final _isStreamStarted = false.obs;

  // 对话相关状态
  final isTalking = false.obs;
  final isConnectingTalk = false.obs;
  WebSocketChannel? _talkWebSocket;

  // 录音器实例
  final FlutterSoundRecorder _flutterSoundRecorder = FlutterSoundRecorder();

  // 录像相关状态
  final isRecording = false.obs;
  final isStartingRecord = false.obs;
  final isStoppingRecord = false.obs;

  // 录像回放相关状态
  final selectedPlaybackTime = Rxn<DateTime>();
  final selectedPlaybackDate = DateTime.now().obs; // 选择的录像日期
  final recordSegments = <Map<String, dynamic>>[].obs;
  final isLoadingRecords = false.obs;
  final isPlayingRecord = false.obs;
  final currentPlaybackStreamId = ''.obs;
  final recordSourceType = 'cloud'.obs; // 录像源类型：'cloud'(云端) 或 'local'(本地)
  final isLoadingPlayback = false.obs; // 是否正在加载回放视频（防抖）
  final showNoRecordMessage = false.obs; // 是否显示"该时段暂无录像"提示
  final showNoAlarmVideoMessage = false.obs; // 是否显示"暂无告警视频"提示

  // 录像数据管理器
  final RecordDataManager _recordDataManager = RecordDataManager();

  // 本地录像片段管理
  final localRecordSegments = <Map<String, dynamic>>[].obs;
  final selectedRecordIds = <String>[].obs; // 选中的录像ID列表
  final isAllSelected = false.obs; // 是否全选

  // 下载模式状态
  final isDownloadMode = false.obs; // 是否处于下载模式

  // 告警视频播放状态
  final isPlayingAlarmVideo = false.obs; // 是否正在播放告警视频

  // 告警历史相关
  final alarmList = <Map<String, dynamic>>[].obs; // 告警消息列表
  final isLoadingAlarms = false.obs; // 是否正在加载告警数据
  final hasMoreAlarms = true.obs; // 是否还有更多告警数据
  final unreadAlarmCount = 0.obs; // 未读告警数量
  final selectedAlarmDate = DateTime.now().obs; // 选择的告警日期
  final selectedAlarmIndex = (-1).obs; // 当前选中的告警索引
  int _alarmCurrentPage = 1; // 当前告警页码
  final int _alarmPageSize = 20; // 每页告警数量

  // 从消息页跳转时的目标告警信息
  String? _targetAlarmId; // 目标告警ID
  String? _targetAlarmTime; // 目标告警时间

  Timer? _audioTimer;
  StreamSubscription<Uint8List>? _audioStreamSubscription;
  Timer? _bufferingTimer; // 缓冲超时定时器
  StreamSubscription<double>? _volumeSubscription; // 系统音量监听订阅

  // 应用生命周期管理（简化版）

  // Getters
  String get deviceId => _deviceId.value;
  String get channelId => _channelId.value;
  String get hsId => _hsId.value;
  // Map<String, dynamic>? get channelDetail => _channelDetail.value;
  String get streamUrl => _streamUrl.value;
  bool get isStreamStarted => _isStreamStarted.value;

  @override
  void onInit() {
    super.onInit();
    _initializeFromArguments();

    // 初始化系统音量监听
    _initSystemVolumeListener();

    // 添加应用生命周期监听
    WidgetsBinding.instance.addObserver(this);

    // 定期更新下载进度显示
    Timer.periodic(Duration(milliseconds: 500), (timer) {
      // 触发UI更新
      update();
    });
  }

  @override
  void onClose() {
    // 移除应用生命周期监听
    WidgetsBinding.instance.removeObserver(this);

    // 停止对话
    _stopTalk();

    // 释放录音器资源
    _flutterSoundRecorder.closeRecorder();

    // 停止录像
    if (isRecording.value) {
      _stopRecording();
    }

    // 停止视频播放
    _videoController?.dispose();

    // 停止直播流
    // _stopStream();

    // 重置录像数据加载状态
    _resetRecordLoadingState();

    // 清理系统音量监听
    _disposeSystemVolumeListener();

    // 确保退出时恢复系统状态
    if (isFullscreen.value) {
      SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
      SystemChrome.setEnabledSystemUIMode(
        SystemUiMode.manual,
        overlays: SystemUiOverlay.values,
      );
    }
    super.onClose();
  }

  /// 应用生命周期状态变化监听
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print('🔄 应用生命周期状态变化: $state');

    switch (state) {
      case AppLifecycleState.resumed:
        _onAppResumed();
        break;
      case AppLifecycleState.paused:
        _onAppPaused();
        break;
      case AppLifecycleState.inactive:
        _onAppInactive();
        break;
      case AppLifecycleState.detached:
        _onAppDetached();
        break;
      case AppLifecycleState.hidden:
        // Android 13+ 新增状态，应用在后台但仍可见
        _onAppHidden();
        break;
    }
  }

  /// 应用恢复到前台
  void _onAppResumed() {
    print('📱 应用恢复到前台，直接重新加载视频');

    // 如果当前在实时预览tab且不是播放告警视频，直接重新加载
    if (currentTabIndex.value == 0 && !isPlayingAlarmVideo.value) {
      print('🔄 直接重新加载视频流');
      reloadVideo();
    }
  }

  /// 应用暂停到后台
  void _onAppPaused() {
    print('📱 应用暂停到后台');

    // 如果正在录像，自动停止录像并保存
    if (isRecording.value && !isStoppingRecord.value) {
      print('📹 检测到正在录像，自动停止录像并保存');
      _stopRecording();
    }
  }

  /// 应用变为非活跃状态（如来电话）
  void _onAppInactive() {
    print('📱 应用变为非活跃状态');

    // 如果正在录像，自动停止录像并保存
    if (isRecording.value && !isStoppingRecord.value) {
      print('📹 检测到正在录像，自动停止录像并保存');
      _stopRecording();
    }
  }

  /// 应用被分离（即将退出）
  void _onAppDetached() {
    print('📱 应用被分离');
  }

  /// 应用隐藏（Android 13+）
  void _onAppHidden() {
    print('📱 应用隐藏');
    // 类似于paused状态的处理
    _onAppPaused();
  }

  /// 从路由参数初始化设备信息
  void _initializeFromArguments() {
    final arguments = Get.arguments as Map<String, dynamic>?;
    if (arguments != null) {
      _hsId.value = arguments['hsId']?.toString() ?? '';
      _deviceId.value = arguments['deviceId']?.toString() ?? '';
      _channelId.value = arguments['channelId']?.toString() ?? '';
      deviceName.value = arguments['deviceName']?.toString() ?? '未知设备';

      // 初始化录像回放时间
      _initializePlaybackTime();

      // 检查是否有目标告警信息（从消息页跳转）
      _targetAlarmId = arguments['targetAlarmId']?.toString();
      _targetAlarmTime = arguments['targetAlarmTime']?.toString();

      // 如果有目标告警时间，根据时间设置告警日期
      if (_targetAlarmTime != null && _targetAlarmTime!.isNotEmpty) {
        try {
          // ✅ 解析UTC时间并转换为北京时间（UTC+8）
          final alarmDateTimeUtc = DateTime.parse(_targetAlarmTime!);
          // 转换为本地时间（北京时间）
          final alarmDateTimeLocal = alarmDateTimeUtc.toLocal();

          selectedAlarmDate.value = DateTime(
            alarmDateTimeLocal.year,
            alarmDateTimeLocal.month,
            alarmDateTimeLocal.day,
          );
          print(
            '🎯 设置告警日期为: ${selectedAlarmDate.value} (UTC时间: $alarmDateTimeUtc, 北京时间: $alarmDateTimeLocal)',
          );
        } catch (e) {
          print('❌ 解析告警时间失败: $e');
        }
      }

      // 检查是否有初始tab参数
      final initialTab = arguments['initialTab'] as int?;
      if (initialTab != null && initialTab >= 0 && initialTab <= 2) {
        currentTabIndex.value = initialTab;
        print('设置初始tab为: $initialTab');

        // 🚀 如果初始tab是告警历史（index 2），立即预加载告警历史数据
        if (initialTab == 2) {
          print('🎯 检测到初始tab为告警历史，开始预加载告警数据...');
          // 立即开始加载告警历史数据，不等待其他初始化完成
          Future.microtask(() async {
            print('📋 预加载告警历史数据开始');
            await loadAlarmHistory(isRefresh: true);
            print('📋 预加载告警历史数据完成');

            // 如果有目标告警ID，查找并定位到该告警
            if (_targetAlarmId != null && _targetAlarmId!.isNotEmpty) {
              _locateTargetAlarm();
            }
          });
        }
      }

      // 检查是否有告警视频URL参数
      final alarmVideoUrl = arguments['alarmVideoUrl']?.toString();
      if (alarmVideoUrl != null && alarmVideoUrl.isNotEmpty) {
        print('🎬 检测到告警视频URL参数，将直接播放告警视频: $alarmVideoUrl');
        // 设置告警视频播放状态
        isPlayingAlarmVideo.value = true;
        // 延迟播放告警视频，等待页面初始化完成
        Future.delayed(const Duration(milliseconds: 1000), () {
          playAlarmVideo(alarmVideoUrl);
        });
      }

      // 检查是否有本地视频路径参数
      final localVideoPath = arguments['localVideoPath']?.toString();
      final isLocalVideo = arguments['isLocalVideo'] as bool? ?? false;
      if (localVideoPath != null && localVideoPath.isNotEmpty && isLocalVideo) {
        print('🎬 检测到本地视频路径参数，将直接播放本地视频: $localVideoPath');
        // 设置本地视频播放状态
        isPlayingAlarmVideo.value = true;
        // 延迟播放本地视频，等待页面初始化完成
        Future.delayed(const Duration(milliseconds: 1000), () {
          playLocalVideo(localVideoPath);
        });
      }

      print(
        '🔧 设备详情页参数：deviceId=${_deviceId.value}, channelId=${_channelId.value}, hsId=${_hsId.value}, initialTab=${initialTab ?? 0}, alarmVideoUrl=${alarmVideoUrl ?? '无'}',
      );

      // 初始化数据和视频
      _initializeData();
    } else {
      print('设备详情页未收到参数');
      BotToast.showText(text: '设备信息获取失败');
    }
  }

  /// 初始化录像回放时间
  void _initializePlaybackTime() {
    final now = DateTime.now();
    selectedPlaybackTime.value = DateTime(
      now.year,
      now.month,
      now.day,
      now.hour,
      now.minute,
      now.second,
    );
  }

  /// 初始化页面数据
  Future<void> _initializeData() async {
    if (_hsId.value.isEmpty) {
      BotToast.showText(text: '设备参数错误');
      return;
    }

    isLoading.value = true;

    try {
      // 🚀 关键初始化数据（通道详情）- 需要等待完成
      await _loadChannelDetail();

      // ✅ 检查设备是否离线
      if (isDeviceOffline && currentTabIndex.value == 0) {
        print('⚠️ 设备已离线，停止初始化流程');
        isLoading.value = false;
        BotToast.showText(text: '该设备已离线');
        return;
      }

      // 检查是否有告警视频URL，如果有则跳过直播流初始化
      final arguments = Get.arguments as Map<String, dynamic>?;
      final alarmVideoUrl = arguments?['alarmVideoUrl']?.toString();

      if (alarmVideoUrl == null || alarmVideoUrl.isEmpty) {
        // 没有告警视频URL时，才初始化直播流
        print('🎬 没有告警视频URL，开始初始化直播流');
        await _startVideoStream();
      } else {
        print('🎬 检测到告警视频URL，跳过直播流初始化，等待告警视频播放');
      }

      // 📹 直接加载今天的录像数据（简化逻辑）- 如果设备离线则跳过
      if (_deviceId.value.isNotEmpty && !isDeviceOffline) {
        print('🎬 开始加载今天的录像数据');
        await loadRecordsForDate();
      } else if (isDeviceOffline) {
        print('⚠️ 设备已离线，跳过加载录像数据');
      }

      // 📋 延迟加载告警历史数据（非关键数据）
      Future.delayed(const Duration(milliseconds: 1000), () {
        final shouldLoadAlarms =
            !(currentTabIndex.value == 2 && alarmList.isNotEmpty);

        if (shouldLoadAlarms) {
          print('🚨 延迟加载告警历史数据');
          loadAlarmHistory(isRefresh: true)
              .then((_) {
                print('✅ 告警历史数据加载完成');
              })
              .catchError((e) {
                print('❌ 告警历史数据加载失败: $e');
              });
        } else {
          print('✅ 告警历史数据已预加载，跳过重复加载（当前有${alarmList.length}条数据）');
        }
      });

      // ✅ 初始化时加载未读告警数量（确保进入设备详情页面时显示正确的未读数）
      Future.delayed(const Duration(milliseconds: 500), () {
        print('📊 初始化时加载未读告警数量');
        _loadUnreadAlarmCount();
      });

      print('🎯 核心初始化完成，其他数据正在后台加载');
    } catch (e) {
      print('初始化数据错误: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      // 如果有告警视频URL，不重置isLoading状态，让playAlarmVideo来管理
      final arguments = Get.arguments as Map<String, dynamic>?;
      final alarmVideoUrl = arguments?['alarmVideoUrl']?.toString();

      if (alarmVideoUrl == null || alarmVideoUrl.isEmpty) {
        isLoading.value = false;
      } else {
        print('🎬 有告警视频URL，保持加载状态直到告警视频播放完成');
      }
    }
  }

  /// 获取通道详情
  Future<void> _loadChannelDetail() async {
    try {
      final response = await _channelService.getChannelDetail(_hsId.value);
      final data = response['data'] as Map<String, dynamic>?;

      if (data != null) {
        channelDetail.value = data;

        // 更新设备名称
        final channelName = data['name']?.toString();
        if (channelName != null && channelName.isNotEmpty) {
          deviceName.value = channelName;
        }

        // 更新通道状态
        final status = data['channelStatus']?.toString() ?? '';
        channelStatus.value = status;
        print('获取通道详情成功: ${data['name']}, 状态: $status');
      }
    } catch (e) {
      print('获取通道详情失败: $e');
    }
  }

  /// 检查设备是否离线
  bool get isDeviceOffline {
    return channelStatus.value == 'OFF';
  }

  /// 开始视频流
  Future<void> _startVideoStream() async {
    if (_deviceId.value.isEmpty) {
      print('设备ID为空，无法开始视频流');
      return;
    }

    try {
      final response = await _videoService.startStream(
        serial: _deviceId.value,
        playType: 'HIS',
      );

      final streamData = response['data'] as Map<String, dynamic>?;
      if (streamData != null) {
        // 提取StreamID
        final streamId = streamData['StreamID']?.toString();
        if (streamId != null && streamId.isNotEmpty) {
          _streamId.value = streamId;
          print('获取到StreamID：$streamId');
        }

        // 直接使用FLV流播放视频
        final flvUrl = streamData['FLV']?.toString();
        if (flvUrl != null && flvUrl.isNotEmpty) {
          _streamUrl.value = flvUrl;
          _isStreamStarted.value = true;
          print('🎬 开始播放FLV视频，流地址：$flvUrl');

          // 直接初始化视频播放器
          await _initializeVideoPlayer();
        } else {
          print('❌ 没有可用的FLV流地址');
          BotToast.showText(text: '网络环境不佳，请稍后尝试');
        }
      }
    } catch (e) {
      print('开始视频流失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 停止视频流
  Future<void> _stopStream() async {
    if (!_isStreamStarted.value ||
        _deviceId.value.isEmpty ||
        _channelId.value.isEmpty) {
      return;
    }

    try {
      // await _videoService.stopStream(
      //   serial: _deviceId.value,
      //   code: _channelId.value,
      //   checkOutputs: false,
      // );

      _isStreamStarted.value = false;
      print('停止直播成功');
    } catch (e) {
      print('停止直播失败: $e');
    }
  }

  /// 初始化视频播放器
  Future<void> _initializeVideoPlayer() async {
    final videoUrl = _streamUrl.value;
    if (videoUrl.isEmpty) {
      print('❌ 没有可用的FLV流地址');
      return;
    }

    try {
      isLoading.value = true;

      // 释放旧的播放器
      if (_videoController != null) {
        _videoController!.removeListener(_onVideoPlayerChanged);
        _videoController!.dispose();
        _videoController = null;
        isVideoInitialized.value = false;
        isPlayingAlarmVideo.value = false;
      }

      print('🎬 开始播放FLV视频: $videoUrl');

      // 创建FLV视频播放器
      _videoController = VideoPlayerController.networkUrl(
        Uri.parse(videoUrl),
        httpHeaders: {
          'User-Agent': 'Flutter Video Player',
          'Accept': 'video/x-flv, video/mp4, */*',
          'Connection': 'keep-alive',
        },
      );

      // 初始化播放器
      await _videoController!.initialize().timeout(
        const Duration(seconds: 20),
        onTimeout: () {
          throw Exception('FLV视频初始化超时');
        },
      );

      isVideoInitialized.value = true;
      _videoController!.addListener(_onVideoPlayerChanged);

      // 设置音量并开始播放
      // 实时预览模式下默认关闭音量
      if (currentTabIndex.value == 0) {
        isMuted.value = true;
      }
      final videoVolume = isMuted.value ? 0.0 : 1.0;
      _videoController!.setVolume(videoVolume);

      // ✅ 实时预览始终使用正常速度（1.0x），不应用自定义倍速
      // VideoPlayerController默认速度为1.0x，无需额外设置

      await _videoController!.play();
      isPlaying.value = true;

      videoErrorMessage.value = '';
      print('✅ FLV视频播放成功');

      isLoading.value = false;
    } catch (e) {
      print('❌ FLV视频播放失败: $e');

      isVideoInitialized.value = false;
      isPlaying.value = false;

      if (_videoController != null) {
        _videoController!.dispose();
        _videoController = null;
      }

      videoErrorMessage.value = 'FLV视频播放失败，请检查网络连接';
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
      isLoading.value = false;
    }
  }

  /// 选择告警项并自动播放对应的视频
  void selectAlarm(int index) {
    if (index >= 0 && index < alarmList.length) {
      selectedAlarmIndex.value = index;
      print('选中告警项: $index');

      // ✅ 获取选中告警的视频URL并自动播放
      final alarm = alarmList[index];
      final videoUrl = alarm['alarmVideo']?.toString();

      if (videoUrl != null && videoUrl.isNotEmpty) {
        print('✅ 选中告警项，准备播放视频: $videoUrl');
        // 重置"暂无告警视频"提示
        showNoAlarmVideoMessage.value = false;
        // 先设置告警视频播放状态，防止被其他逻辑停止
        isPlayingAlarmVideo.value = true;
        // 自动播放告警视频
        playAlarmVideo(videoUrl);
      } else {
        print('❌ 选中告警项没有视频URL，停止当前视频');
        // 停止当前视频并显示"暂无告警视频"提示
        stopCurrentVideoAndShowNoAlarmVideo();
      }
    }
  }

  /// 播放告警视频
  Future<void> playAlarmVideo(String videoUrl, {int? seekOffsetSeconds}) async {
    if (videoUrl.isEmpty) {
      print('❌ 视频地址为空');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
      return;
    }

    try {
      print('🎬 开始播放视频');
      print('📍 视频URL: $videoUrl');
      print(
        '📊 当前状态 - isLoading: ${isLoading.value}, isVideoInitialized: ${isVideoInitialized.value}',
      );

      isLoading.value = true;
      isBuffering.value = false;
      isPlayingAlarmVideo.value = true; // 设置告警视频播放状态
      showNoAlarmVideoMessage.value = false; // 重置"暂无告警视频"提示

      // 停止直播流，避免资源冲突 - 已移除，避免不必要的API调用
      // if (_isStreamStarted.value) {
      //   print('🔄 停止直播流，避免资源冲突');
      //   await _stopStream();
      //   await Future.delayed(const Duration(milliseconds: 500));
      // }

      // 释放旧的播放器
      if (_videoController != null) {
        print('🔄 清理当前视频播放器');
        try {
          _videoController!.removeListener(_onVideoPlayerChanged);
          _videoController!.dispose();
          _videoController = null;
          isVideoInitialized.value = false;
          isPlaying.value = false;
        } catch (e) {
          print('⚠️ 清理旧播放器时出错: $e');
        }
      }

      // 等待一小段时间确保资源清理完成
      await Future.delayed(const Duration(milliseconds: 500));

      // 初始化新的视频播放器
      print('🎬 初始化视频播放器');
      print('🔗 创建VideoPlayerController，URL: $videoUrl');

      _videoController = VideoPlayerController.networkUrl(
        Uri.parse(videoUrl),
        httpHeaders: {
          'User-Agent': 'Flutter Video Player',
          'Accept': '*/*',
          'Connection': 'keep-alive',
        },
      );

      print('⏳ 开始初始化视频播放器（超时20秒）...');

      await _videoController!.initialize().timeout(
        const Duration(seconds: 20), // 增加超时时间到20秒
        onTimeout: () {
          print('❌ 视频初始化超时（20秒）');
          throw Exception('视频初始化超时');
        },
      );

      print('✅ 视频播放器初始化成功');

      isVideoInitialized.value = true;
      _videoController!.addListener(_onVideoPlayerChanged);

      // 根据当前静音状态设置视频播放器音量
      final videoVolume = isMuted.value ? 0.0 : 1.0;
      _videoController!.setVolume(videoVolume);
      print('🔊 设置音量: $videoVolume');

      // ✅ 应用当前的播放速度（只在录像回放和告警视频时）
      if ((currentTabIndex.value == 1 || currentTabIndex.value == 2) &&
          playbackSpeed.value != 1.0) {
        _videoController!.setPlaybackSpeed(playbackSpeed.value);
        print('🎬 应用播放速度: ${playbackSpeed.value}x');
      }

      // 自动开始播放
      print('▶️ 开始播放视频');
      await _videoController!.play();
      isPlaying.value = true;

      // ✅ 如果有偏移秒数，定位到指定位置
      if (seekOffsetSeconds != null && seekOffsetSeconds > 0) {
        print('⏩ 定位到偏移位置: ${seekOffsetSeconds}秒');
        // 等待播放器准备就绪后再定位
        await Future.delayed(const Duration(milliseconds: 500));
        try {
          final seekPosition = Duration(seconds: seekOffsetSeconds);
          await _videoController!.seekTo(seekPosition);
          print('✅ 已定位到: ${seekPosition.inSeconds}秒');
        } catch (e) {
          print('⚠️ 定位失败: $e');
        }
      }

      // ✅ 视频开始播放时，显示暂停按钮（3秒后自动隐藏）
      showPlayPauseButton.value = true;
      Future.delayed(const Duration(seconds: 3), () {
        if (_videoController != null && _videoController!.value.isPlaying) {
          showPlayPauseButton.value = false;
        }
      });

      print('✅ 视频播放成功');
      BotToast.showText(text: '正在播放视频');
    } catch (e) {
      print('❌ 视频播放器初始化失败: $e');
      print('📝 错误详情: ${e.toString()}');
      print('📝 错误类型: ${e.runtimeType}');

      bool playbackSuccess = false;

      // 检查是否是M3U8格式的视频
      if (videoUrl.contains('.m3u8')) {
        print('🎬 检测到M3U8格式视频，尝试使用FVP播放器');
        try {
          // 尝试使用FVP播放器播放M3U8视频
          await _playM3U8Video(videoUrl, seekOffsetSeconds: seekOffsetSeconds);
          playbackSuccess = true; // M3U8播放成功
        } catch (m3u8Error) {
          print('❌ M3U8视频播放也失败: $m3u8Error');
          playbackSuccess = false; // M3U8播放失败
        }

        // 如果M3U8播放成功，直接返回
        if (playbackSuccess) {
          return;
        }
      } else if (e.toString().contains('invalid or unsupported media')) {
        print('🎬 视频格式不支持或URL无效');
        BotToast.showText(text: '视频格式不支持，请检查视频源');
      } else {
        BotToast.showText(text: '视频播放失败，请稍后重试');
      }

      // 清理失败的播放器
      if (_videoController != null) {
        try {
          _videoController!.dispose();
        } catch (disposeError) {
          print('⚠️ 清理失败播放器时出错: $disposeError');
        }
        _videoController = null;
        isVideoInitialized.value = false;
        isPlaying.value = false;
      }

      // ✅ 所有播放方式都失败，显示"该告警暂无视频"提示
      showNoAlarmVideoMessage.value = true;

      // 重置告警视频状态，允许重试
      isPlayingAlarmVideo.value = false;
    } finally {
      isLoading.value = false;
      print('🔄 播放流程结束，isLoading已重置为false');
    }
  }

  /// 播放本地视频
  Future<void> playLocalVideo(String localVideoPath) async {
    if (localVideoPath.isEmpty) {
      print('没有可用的本地视频路径');
      BotToast.showText(text: '本地视频路径不存在');
      return;
    }

    try {
      print('🎬 开始播放本地视频，路径: $localVideoPath');
      isLoading.value = true;
      isBuffering.value = false;
      isPlayingAlarmVideo.value = true; // 设置本地视频播放状态

      // 检查文件是否存在
      final file = File(localVideoPath);
      if (!await file.exists()) {
        throw Exception('本地视频文件不存在');
      }

      // 获取文件信息
      final fileSize = await file.length();
      print('📁 本地视频文件信息:');
      print('  路径: $localVideoPath');
      print('  大小: ${_formatBytes(fileSize)}');

      // 停止直播流，避免资源冲突 - 已移除，避免不必要的API调用
      // if (_isStreamStarted.value) {
      //   print('🔄 停止直播流，避免与本地视频冲突');
      //   await _stopStream();
      //   await Future.delayed(const Duration(milliseconds: 500));
      // }

      // 释放旧的播放器
      if (_videoController != null) {
        print('🔄 清理当前视频播放器');
        _videoController!.removeListener(_onVideoPlayerChanged);
        _videoController!.dispose();
        _videoController = null;
        isVideoInitialized.value = false;
        isPlaying.value = false;
      }

      // 等待一小段时间确保资源清理完成
      await Future.delayed(const Duration(milliseconds: 300));

      // 初始化本地视频播放器
      print('🎬 初始化本地视频播放器');
      _videoController = VideoPlayerController.file(file);
      await _videoController!.initialize().timeout(
        const Duration(seconds: 10),
        onTimeout: () {
          throw Exception('本地视频初始化超时');
        },
      );

      isVideoInitialized.value = true;
      _videoController!.addListener(_onVideoPlayerChanged);

      // 根据当前静音状态设置视频播放器音量
      final videoVolume = isMuted.value ? 0.0 : 1.0;
      _videoController!.setVolume(videoVolume);
      print('🔊 本地视频播放器初始化时设置音量: $videoVolume');

      // ✅ 应用当前的播放速度（只在录像回放和告警视频时）
      if ((currentTabIndex.value == 1 || currentTabIndex.value == 2) &&
          playbackSpeed.value != 1.0) {
        _videoController!.setPlaybackSpeed(playbackSpeed.value);
        print('🎬 应用播放速度: ${playbackSpeed.value}x');
      }

      // 自动开始播放
      await _videoController!.play();
      isPlaying.value = true;

      print('✅ 本地视频播放器初始化成功');
      BotToast.showText(text: '正在播放本地视频');
    } catch (e) {
      print('❌ 本地视频播放器初始化失败: $e');
      BotToast.showText(text: '本地视频播放失败，请稍后重试');

      // 清理失败的播放器
      if (_videoController != null) {
        _videoController!.dispose();
        _videoController = null;
        isVideoInitialized.value = false;
        isPlaying.value = false;
      }
    } finally {
      isLoading.value = false;
    }
  }

  /// 格式化字节数
  String _formatBytes(int bytes) {
    if (bytes < 1024) return '${bytes}B';
    if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
    if (bytes < 1024 * 1024 * 1024)
      return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
    return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
  }

  // 录像回放相关方法

  /// 视频播放器状态监听
  void _onVideoPlayerChanged() {
    if (_videoController != null) {
      final value = _videoController!.value;
      final wasPlaying = isPlaying.value;
      isPlaying.value = value.isPlaying;
      isBuffering.value = value.isBuffering;

      // ✅ 当视频从播放变为暂停时，显示播放按钮
      if (wasPlaying && !value.isPlaying) {
        showPlayPauseButton.value = true;
      }

      // // 添加详细的状态日志
      // print('🎥 视频播放器状态更新:');
      // print('🎥 - 是否播放中: ${value.isPlaying}');
      // print('🎥 - 是否初始化: ${value.isInitialized}');
      // print('🎥 - 是否缓冲中: ${value.isBuffering}');
      // print('🎥 - 视频大小: ${value.size}');
      // print('🎥 - 播放位置: ${value.position}');
      // print('🎥 - 总时长: ${value.duration}');

      // 检查是否有错误
      if (value.hasError) {
        print('❌ 视频播放器错误: ${value.errorDescription}');
        isBuffering.value = false; // 出错时停止缓冲状态
        BotToast.showText(text: '视频播放出错，请重试');
      }

      // 检查是否长时间缓冲
      if (value.isBuffering) {
        print('⏳ 视频正在缓冲中...');

        // 启动缓冲超时定时器
        _bufferingTimer?.cancel();
        _bufferingTimer = Timer(const Duration(seconds: 10), () {
          print('⚠️ 视频缓冲超时，可能网络有问题');
          BotToast.showText(text: '视频加载缓慢，请检查网络连接');
        });
      } else {
        // 取消缓冲超时定时器
        _bufferingTimer?.cancel();
        _bufferingTimer = null;

        if (value.isPlaying) {
          // print('▶️ 视频正在正常播放');
        }
      }
    }
  }

  /// 播放/暂停视频
  void togglePlayPause() {
    if (_videoController != null && isVideoInitialized.value) {
      // ✅ 显示暂停/播放按钮（点击时显示）
      showPlayPauseButton.value = true;

      if (_videoController!.value.isPlaying) {
        _videoController!.pause();
      } else {
        _videoController!.play();
      }

      // ✅ 3秒后自动隐藏按钮
      Future.delayed(const Duration(seconds: 3), () {
        if (_videoController != null && _videoController!.value.isPlaying) {
          showPlayPauseButton.value = false;
        }
      });
    }
  }

  /// 切换静音状态
  void toggleMute() {
    if (_videoController != null && isVideoInitialized.value) {
      final newVolume = isMuted.value ? 1.0 : 0.0;
      _videoController!.setVolume(newVolume);
      isMuted.value = !isMuted.value;
      print('音频状态切换: ${isMuted.value ? "静音" : "播放声音"}');
    }
  }

  /// 设置播放速度（只在录像回放和告警视频时有效）
  void setPlaybackSpeed(double speed) {
    if (_videoController != null && isVideoInitialized.value) {
      // 只在录像回放或告警视频时允许倍速播放
      if (currentTabIndex.value == 1 || currentTabIndex.value == 2) {
        _videoController!.setPlaybackSpeed(speed);
        playbackSpeed.value = speed;
        print('🎬 播放速度设置为: ${speed}x');

        // 显示提示
        String speedText;
        if (speed == 0.5) {
          speedText = '0.5倍速';
        } else if (speed == 1.0) {
          speedText = '正常速度';
        } else {
          speedText = '${speed.toInt()}倍速';
        }
        // Get.snackbar(
        //   '播放速度',
        //   '已切换到$speedText',
        //   duration: const Duration(seconds: 1),
        //   snackPosition: SnackPosition.BOTTOM,
        //   margin: const EdgeInsets.only(bottom: 100, left: 20, right: 20),
        // );
      } else {
        print('⚠️ 实时预览不支持倍速播放');
      }
    }
  }

  /// 初始化系统音量监听器
  Future<void> _initSystemVolumeListener() async {
    try {
      print('🔊 开始初始化系统音量监听器');

      // 进入实时预览时，默认关闭音量开关（与系统音量无关联）
      isMuted.value = true;
      print('🔊 初始静音状态: ${isMuted.value}（默认关闭）');

      // 如果视频控制器已初始化，同步音量状态到视频播放器
      if (_videoController != null && isVideoInitialized.value) {
        final videoVolume = isMuted.value ? 0.0 : 1.0;
        _videoController!.setVolume(videoVolume);
        print('🔊 同步视频播放器音量: $videoVolume');
      }

      // 不再监听系统音量变化，因为音量开关与系统音量无关联
      print('✅ 音量控制初始化成功（独立于系统音量）');
    } catch (e) {
      print('❌ 初始化音量控制失败: $e');
      // 初始化失败时设置默认状态
      isMuted.value = true;
    }
  }

  /// 清理系统音量监听器
  void _disposeSystemVolumeListener() {
    try {
      print('🔊 开始清理音量控制');

      // 取消音量变化监听（如果存在）
      _volumeSubscription?.cancel();
      _volumeSubscription = null;

      // 移除FlutterVolumeController的监听器（如果存在）
      try {
        FlutterVolumeController.removeListener();
      } catch (e) {
        // 忽略错误，因为可能没有添加监听器
      }

      print('✅ 音量控制清理完成');
    } catch (e) {
      print('❌ 清理音量控制失败: $e');
    }
  }

  /// 显示通道信息弹出框
  void showChannelInfo() {
    if (channelDetail.value == null) {
      BotToast.showText(text: '通道信息获取中，请稍后再试');
      return;
    }

    print('显示通道信息弹出框');
    // 弹出框将在视图中实现
  }

  /// 切换回直播源
  Future<void> _switchToLiveStream() async {
    try {
      print('🔄 开始切换回直播源...');

      // 显示加载状态
      isLoading.value = true;
      isVideoInitialized.value = false;
      isPlaying.value = false;

      // 重置非直播源状态
      isPlayingAlarmVideo.value = false;
      isPlayingRecord.value = false;

      // 停止当前视频播放器
      if (_videoController != null) {
        print('🔄 停止当前视频播放器');
        _videoController!.removeListener(_onVideoPlayerChanged);
        _videoController!.dispose();
        _videoController = null;
      }

      // 停止当前直播流 - 已移除，避免不必要的API调用
      // if (_isStreamStarted.value) {
      //   print('🔄 停止当前直播流');
      //   await _stopStream();
      // }

      // 等待一小段时间确保资源清理完成
      await Future.delayed(const Duration(milliseconds: 500));

      // 重新开始直播流，获取最新地址
      print('🔄 重新开始直播流，获取最新地址...');
      await _startVideoStream();

      print('✅ 成功切换回直播源');
      BotToast.showText(text: '已切换到实时预览');
    } catch (e) {
      print('❌ 切换回直播源失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      // 确保加载状态被重置
      isLoading.value = false;
    }
  }

  /// 自动播放最新的录像
  Future<void> _autoPlayLatestRecord() async {
    // 防抖：如果正在加载回放视频，跳过
    if (isLoadingPlayback.value) {
      print('⏳ 回放视频正在加载中，跳过本次请求');
      return;
    }

    // 防抖：如果已经在播放录像，跳过
    if (isPlayingRecord.value && isVideoInitialized.value) {
      print('✅ 已经在播放录像，跳过自动播放');
      return;
    }

    try {
      print('🎬 开始自动播放最新录像');

      // 根据当前录像源类型选择对应的数据列表
      final segments =
          recordSourceType.value == 'cloud'
              ? recordSegments
              : localRecordSegments;

      if (segments.isEmpty) {
        print('📋 录像列表为空，无法自动播放');
        return;
      }

      // 找到最新的录像片段（按开始时间排序，取最后一个）
      final sortedSegments = List<Map<String, dynamic>>.from(segments);
      sortedSegments.sort((a, b) {
        final startTimeA = a['startTime'] as DateTime?;
        final startTimeB = b['startTime'] as DateTime?;
        if (startTimeA == null || startTimeB == null) return 0;
        return startTimeA.compareTo(startTimeB);
      });

      final latestSegment = sortedSegments.last;
      print(
        '🎬 找到最新录像片段: ${latestSegment['startTime']} - ${latestSegment['endTime']}',
      );

      // 设置播放时间为该片段的开始时间
      final startTime = latestSegment['startTime'] as DateTime?;
      if (startTime != null) {
        selectedPlaybackTime.value = startTime;
        print('🎬 设置播放时间为: ${startTime}');

        // 播放该录像片段
        await _loadPlaybackVideo(startTime);
      }
    } catch (e) {
      print('❌ 自动播放最新录像失败: $e');
    }
  }

  /// 等待告警列表加载完成后再播放视频
  Future<void> _waitForAlarmListAndPlay() async {
    print('⏳ 开始等待告警列表加载完成...');

    // ✅ 如果正在加载，等待加载完成（最多等待30秒）
    double maxWaitTime = 30.0; // 最大等待时间（秒）
    double waitedTime = 0.0;
    const checkInterval = Duration(milliseconds: 500); // 每500ms检查一次

    while (isLoadingAlarms.value && waitedTime < maxWaitTime) {
      // ✅ 检查是否还在告警消息tab，如果切换了tab，就不播放
      if (currentTabIndex.value != 2) {
        print('⚠️ 用户已切换到其他tab，取消等待播放');
        return;
      }

      print('⏳ 告警列表正在加载中，已等待 ${waitedTime.toStringAsFixed(1)}秒...');
      await Future.delayed(checkInterval);
      waitedTime += 0.5;
    }

    // ✅ 再次检查是否还在告警消息tab
    if (currentTabIndex.value != 2) {
      print('⚠️ 用户已切换到其他tab，取消播放');
      return;
    }

    if (isLoadingAlarms.value) {
      print('⚠️ 告警列表加载超时（${maxWaitTime}秒），停止当前视频并显示提示');
      stopCurrentVideoAndShowNoAlarmVideo();
      return;
    }

    print('✅ 告警列表加载完成，开始检查并播放视频');
    // ✅ 加载完成后，再播放视频
    _autoPlayLatestAlarm();
  }

  /// 自动播放最新的告警视频
  Future<void> _autoPlayLatestAlarm() async {
    try {
      print('🚨 开始自动播放最新告警视频');

      // ✅ 确保不在加载中
      if (isLoadingAlarms.value) {
        print('⏳ 告警列表正在加载中，等待加载完成...');
        _waitForAlarmListAndPlay();
        return;
      }

      if (alarmList.isEmpty) {
        print('📋 告警列表为空，无法自动播放，停止当前视频并显示提示');
        // ✅ 告警列表为空时，停止当前视频并显示"暂无告警视频"提示
        stopCurrentVideoAndShowNoAlarmVideo();
        return;
      }

      // 找到最新的告警（按时间排序，取第一个，因为通常是最新的）
      final latestAlarm = alarmList.first;
      final videoUrl = latestAlarm['alarmVideo']?.toString();

      // ✅ 切换到告警消息页面时，自动标记第一条未读告警为已读
      final msgId = latestAlarm['id']?.toString();
      if (msgId != null) {
        // 判断是否为未读状态
        final readStatus = latestAlarm['readStatus'];
        final read = latestAlarm['read'];
        final isUnread =
            (readStatus != 1 && readStatus != null) ||
            (read != true && read != null) ||
            (readStatus == null && read == null);

        // 如果是未读状态，立即标记为已读
        if (isUnread) {
          print('📖 自动播放第一条告警，立即标记为已读: $msgId');
          await markAlarmRead(msgId);
        }
      }

      if (videoUrl != null && videoUrl.isNotEmpty) {
        print('🎬 找到最新告警视频: $videoUrl');
        // 设置选中状态为第一个告警
        selectedAlarmIndex.value = 0;
        await playAlarmVideo(videoUrl);
      } else {
        print('📋 最新告警无视频地址，停止当前视频并显示提示');
        // ✅ 告警无视频地址时，停止当前视频并显示"暂无告警视频"提示
        stopCurrentVideoAndShowNoAlarmVideo();
      }
    } catch (e) {
      print('❌ 自动播放最新告警视频失败: $e');
      // ✅ 播放失败时，停止当前视频并显示提示
      stopCurrentVideoAndShowNoAlarmVideo();
    }
  }

  /// 播放指定的告警视频（从消息页面跳转过来）
  Future<void> _playSpecificAlarmVideo(String alarmVideoUrl) async {
    try {
      print('🎬 开始播放指定告警视频: $alarmVideoUrl');

      // 先加载告警历史数据
      if (alarmList.isEmpty) {
        print('📋 告警列表为空，先加载告警历史');
        await loadAlarmHistory(isRefresh: true);
      }

      // 在告警列表中查找匹配的告警项
      int matchingIndex = -1;
      for (int i = 0; i < alarmList.length; i++) {
        final alarm = alarmList[i];
        final videoUrl = alarm['alarmVideo']?.toString();
        if (videoUrl == alarmVideoUrl) {
          matchingIndex = i;
          break;
        }
      }

      if (matchingIndex >= 0) {
        print('🎯 找到匹配的告警项，索引: $matchingIndex');
        // 设置选中状态为匹配的告警
        selectedAlarmIndex.value = matchingIndex;
        await playAlarmVideo(alarmVideoUrl);
      } else {
        print('⚠️ 未找到匹配的告警项，直接播放视频');
        // 即使没找到匹配项，也直接播放视频
        selectedAlarmIndex.value = 0; // 默认选中第一个
        await playAlarmVideo(alarmVideoUrl);
      }
    } catch (e) {
      print('❌ 播放指定告警视频失败: $e');
      BotToast.showText(text: '播放告警视频失败');
    }
  }

  /// 切换底部tab
  void changeTab(int index) {
    print('🔄 切换到tab: $index');
    currentTabIndex.value = index;

    // 如果切换到实时预览tab（索引0），重新加载实时视频
    if (index == 0) {
      print('📺 切换到实时预览tab');

      // 重置播放速度为正常速度
      if (playbackSpeed.value != 1.0) {
        playbackSpeed.value = 1.0;
        if (_videoController != null && isVideoInitialized.value) {
          _videoController!.setPlaybackSpeed(1.0);
          print('🎬 切换到实时预览，播放速度重置为1.0x');
        }
      }

      // 重置音量为静音状态
      isMuted.value = true;
      if (_videoController != null && isVideoInitialized.value) {
        _videoController!.setVolume(0.0);
        print('🔊 切换到实时预览，音量重置为静音');
      }

      // 无论当前播放什么，都重新加载实时视频
      print('🔄 重新加载实时视频画面');
      reloadVideo();
    }

    // 如果切换到录像回放tab（索引1），自动播放最新的录像
    if (index == 1) {
      print('🎬 切换到录像回放tab');

      // 立即重置"无录像"提示状态，确保不会显示错误提示
      showNoRecordMessage.value = false;
      showNoAlarmVideoMessage.value = false; // ✅ 重置告警提示状态
      print('🔄 重置showNoRecordMessage为false');

      // ✅ 无论当前播放什么（实时预览、告警视频或其他），都要先停止，避免冲突
      if (isVideoInitialized.value) {
        print('⏸️ 切换到录像回放，停止当前视频（可能是实时预览、告警视频或录像）');
        // 强制停止所有类型的视频，包括告警视频
        _stopAllVideoAsync();
      }

      // 简单逻辑：如果有录像数据就播放，没有就显示提示
      final segments =
          recordSourceType.value == 'cloud'
              ? recordSegments
              : localRecordSegments;

      if (segments.isNotEmpty) {
        print('📋 录像数据已加载，准备自动播放最新录像');
        _autoPlayLatestRecord();
      } else {
        print('📋 录像列表为空，显示无录像提示');
        showNoRecordMessage.value = true;
      }
    }

    // 如果切换到告警历史tab（索引2），智能处理数据加载并自动播放最新告警视频
    if (index == 2) {
      print('📋 切换到告警历史tab，当前告警列表数量: ${alarmList.length}');
      print('📋 是否正在加载: ${isLoadingAlarms.value}');
      print('📋 是否正在播放告警视频: ${isPlayingAlarmVideo.value}');
      print('📋 是否正在播放录像: ${isPlayingRecord.value}');

      // ✅ 重置提示状态
      showNoRecordMessage.value = false; // ✅ 重置录像提示状态
      showNoAlarmVideoMessage.value = false; // ✅ 重置告警提示状态

      // ✅ 切换到告警历史tab时，刷新未读告警数量（确保显示最新的未读数）
      _loadUnreadAlarmCount();

      // ✅ 无论当前播放什么（实时预览、录像回放或其他），都要先停止，避免冲突
      // ✅ 注意：即使是告警视频，切换tab时也要重新加载，确保数据一致性
      if (isVideoInitialized.value) {
        print('⏸️ 切换到告警消息，停止当前视频（可能是实时预览、录像回放或告警视频）');
        // 强制停止所有类型的视频
        _stopAllVideoAsync();
      }

      // 检查是否从消息页面跳转过来，有特定的告警视频URL
      final arguments = Get.arguments as Map<String, dynamic>?;
      final alarmVideoUrl = arguments?['alarmVideoUrl']?.toString();

      if (alarmVideoUrl != null && alarmVideoUrl.isNotEmpty) {
        print('🎬 从消息页面跳转，直接播放指定告警视频: $alarmVideoUrl');
        // 直接播放指定的告警视频
        _playSpecificAlarmVideo(alarmVideoUrl);
      } else {
        // ✅ 优化加载逻辑：等待加载完成后再播放
        if (alarmList.isEmpty && !isLoadingAlarms.value) {
          print('📋 告警列表为空且未在加载，主动加载告警历史');
          // 先加载告警历史
          loadAlarmHistory(isRefresh: true)
              .then((_) {
                print('✅ 告警历史加载完成，开始检查并播放视频');
                // ✅ 加载完成后，确保加载状态已重置，再播放视频
                _waitForAlarmListAndPlay();
              })
              .catchError((e) {
                print('❌ 加载告警历史失败: $e');
                // 加载失败时，停止当前视频并显示提示
                stopCurrentVideoAndShowNoAlarmVideo();
              });
        } else if (alarmList.isNotEmpty) {
          print('📋 告警列表已有${alarmList.length}条数据，直接播放最新告警视频');
          // ✅ 确保不在加载中，再播放
          if (!isLoadingAlarms.value) {
            _autoPlayLatestAlarm();
          } else {
            print('⏳ 告警列表有数据但正在加载中，等待加载完成...');
            _waitForAlarmListAndPlay();
          }
        } else {
          print('📋 告警数据正在加载中...（预加载或其他加载进程）');
          // ✅ 等待加载完成后自动播放
          _waitForAlarmListAndPlay();
        }
      }
    }
  }

  /// 停止当前视频播放（异步，不阻塞UI）
  /// ⚠️ 注意：如果正在播放告警视频，不会停止（保留原有逻辑）
  void _stopCurrentVideoAsync() {
    // ✅ 如果正在播放告警视频，不要停止，避免打断用户操作
    if (isPlayingAlarmVideo.value) {
      print('⚠️ 正在播放告警视频，跳过停止操作');
      return;
    }

    print('⏹️ 立即停止当前视频播放（异步）');

    // 1️⃣ 立即重置UI状态，让视频画面立刻消失
    isVideoInitialized.value = false;
    isPlaying.value = false;
    isBuffering.value = false;
    isPlayingRecord.value = false; // ✅ 重置录像播放状态
    print('✅ UI状态已立即重置');

    // 2️⃣ 异步清理视频资源，不阻塞UI
    Future.microtask(() async {
      try {
        print('🔄 开始异步清理视频资源');

        // 清理视频控制器
        if (_videoController != null) {
          try {
            _videoController!.removeListener(_onVideoPlayerChanged);
            await _videoController!.pause();
            await _videoController!.dispose();
            _videoController = null;
            print('✅ 视频控制器已清理');
          } catch (e) {
            print('⚠️ 清理视频控制器时出错: $e');
          }
        }

        // 停止直播流 - 已移除，避免不必要的API调用
        // if (_isStreamStarted.value) {
        //   await _stopStream();
        //   print('✅ 直播流已停止');
        // }

        print('✅ 视频资源清理完成');
      } catch (e) {
        print('❌ 异步清理视频资源时出错: $e');
      }
    });
  }

  /// 强制停止所有类型的视频播放（包括告警视频）- 用于tab切换时
  void _stopAllVideoAsync() {
    print('⏹️ 强制停止所有类型的视频播放（包括告警视频）');

    // 1️⃣ 立即重置UI状态，让视频画面立刻消失
    isVideoInitialized.value = false;
    isPlaying.value = false;
    isBuffering.value = false;
    isPlayingRecord.value = false; // ✅ 重置录像播放状态
    isPlayingAlarmVideo.value = false; // ✅ 重置告警视频播放状态
    print('✅ UI状态已立即重置（包括告警视频状态）');

    // 2️⃣ 异步清理视频资源，不阻塞UI
    Future.microtask(() async {
      try {
        print('🔄 开始异步清理视频资源（强制模式）');

        // 清理视频控制器
        if (_videoController != null) {
          try {
            _videoController!.removeListener(_onVideoPlayerChanged);
            await _videoController!.pause();
            await _videoController!.dispose();
            _videoController = null;
            print('✅ 视频控制器已清理');
          } catch (e) {
            print('⚠️ 清理视频控制器时出错: $e');
          }
        }

        // 停止直播流 - 已移除，避免不必要的API调用
        // if (_isStreamStarted.value) {
        //   await _stopStream();
        //   print('✅ 直播流已停止');
        // }

        print('✅ 视频资源清理完成（强制模式）');
      } catch (e) {
        print('❌ 异步清理视频资源时出错: $e');
      }
    });
  }

  /// 停止当前视频播放（公共方法）
  void stopCurrentVideo() {
    _stopCurrentVideoAsync();
    // 只有在录像回放模式下才显示"该时段暂无录像"提示
    if (currentTabIndex.value == 1) {
      showNoRecordMessage.value = true;
    }
  }

  /// 停止当前视频并显示"暂无告警视频"提示
  void stopCurrentVideoAndShowNoAlarmVideo() {
    _stopCurrentVideoAsync();
    // 重置其他提示状态
    showNoRecordMessage.value = false;
    // 显示"暂无告警视频"提示
    showNoAlarmVideoMessage.value = true;
  }

  /// 使用FVP播放器播放M3U8视频
  Future<void> _playM3U8Video(String videoUrl, {int? seekOffsetSeconds}) async {
    try {
      print('🎬 使用FVP播放器播放M3U8视频: $videoUrl');

      // 清理旧的播放器
      if (_videoController != null) {
        _videoController!.removeListener(_onVideoPlayerChanged);
        _videoController!.dispose();
        _videoController = null;
      }

      // 创建FVP播放器
      _videoController = VideoPlayerController.networkUrl(
        Uri.parse(videoUrl),
        httpHeaders: {
          'User-Agent': 'Flutter Video Player',
          'Accept': 'application/vnd.apple.mpegurl, application/x-mpegurl, */*',
          'Connection': 'keep-alive',
        },
        // 使用FVP的配置
        videoPlayerOptions: VideoPlayerOptions(
          mixWithOthers: true,
          allowBackgroundPlayback: false,
        ),
      );

      print('⏳ 开始初始化FVP播放器（超时30秒）...');

      await _videoController!.initialize().timeout(
        const Duration(seconds: 30),
        onTimeout: () {
          throw Exception('FVP播放器初始化超时');
        },
      );

      print('✅ FVP播放器初始化成功');

      isVideoInitialized.value = true;
      _videoController!.addListener(_onVideoPlayerChanged);

      // 设置音量和播放速度
      final videoVolume = isMuted.value ? 0.0 : 1.0;
      _videoController!.setVolume(videoVolume);

      if ((currentTabIndex.value == 1 || currentTabIndex.value == 2) &&
          playbackSpeed.value != 1.0) {
        _videoController!.setPlaybackSpeed(playbackSpeed.value);
      }

      // 开始播放
      await _videoController!.play();
      isPlaying.value = true;
      isPlayingAlarmVideo.value = true;

      // ✅ 如果有偏移秒数，定位到指定位置
      if (seekOffsetSeconds != null && seekOffsetSeconds > 0) {
        print('⏩ M3U8定位到偏移位置: ${seekOffsetSeconds}秒');
        // 等待播放器准备就绪后再定位
        await Future.delayed(const Duration(milliseconds: 800));
        try {
          final seekPosition = Duration(seconds: seekOffsetSeconds);
          await _videoController!.seekTo(seekPosition);
          print('✅ M3U8已定位到: ${seekPosition.inSeconds}秒');
        } catch (e) {
          print('⚠️ M3U8定位失败: $e');
        }
      }

      print('✅ M3U8视频播放成功');
      BotToast.showText(text: '正在播放视频');
    } catch (e) {
      print('❌ FVP播放器初始化失败: $e');
      BotToast.showText(text: 'M3U8视频播放失败，请检查网络连接');

      // 清理失败的播放器
      if (_videoController != null) {
        try {
          _videoController!.dispose();
        } catch (disposeError) {
          print('⚠️ 清理FVP播放器时出错: $disposeError');
        }
        _videoController = null;
        isVideoInitialized.value = false;
        isPlaying.value = false;
        isPlayingAlarmVideo.value = false;
      }

      // ✅ M3U8播放失败时，重新抛出异常，让调用者知道播放失败
      rethrow;
    } finally {
      isLoading.value = false;
    }
  }

  /// 对话功能
  Future<void> startTalk() async {
    if (isTalking.value) {
      // 如果正在对话，则结束对话
      await _stopTalk();
      return;
    }

    // ✅ 检查设备是否离线
    if (isDeviceOffline) {
      BotToast.showText(text: '设备已离线');
      return;
    }

    if (_deviceId.value.isEmpty || _channelId.value.isEmpty) {
      BotToast.showText(text: '设备信息不完整');
      return;
    }

    // 检查录音权限
    final hasPermission = await _checkMicrophonePermission();
    if (!hasPermission) {
      return; // 权限检查失败，已在 _checkMicrophonePermission 中处理
    }

    isConnectingTalk.value = true;

    // 保存对话前的音量状态
    wasMutedBeforeTalk.value = isMuted.value;

    // 如果当前是静音状态，则开启音量
    if (isMuted.value) {
      isMuted.value = false;
      if (_videoController != null) {
        _videoController!.setVolume(1.0);
      }
      print('🔊 对话开始，自动开启音量');
    }

    try {
      // 获取对讲地址
      final response = await _videoService.getTalkUrl(
        serial: _deviceId.value,
        code: _channelId.value,
      );

      final talkUrl = response['data'] as String?;
      if (talkUrl != null && talkUrl.isNotEmpty) {
        print('获取对讲地址成功: $talkUrl');

        // 连接WebSocket
        await _connectTalkWebSocket(talkUrl);

        // 开始录音
        await _startAudioRecording();

        isTalking.value = true;
        BotToast.showText(text: '对话已开始');
      } else {
        throw Exception('获取对讲地址失败');
      }
    } catch (e) {
      print('开始对话失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      isConnectingTalk.value = false;
    }
  }

  /// 停止对话
  Future<void> _stopTalk() async {
    try {
      // 停止录音
      await _stopAudioRecording();

      // 断开WebSocket连接
      _talkWebSocket?.sink.close();
      _talkWebSocket = null;

      // 取消定时器
      _audioTimer?.cancel();
      _audioTimer = null;

      _bufferingTimer?.cancel();
      _bufferingTimer = null;

      isTalking.value = false;

      // 对话结束时的音量控制逻辑
      if (wasMutedBeforeTalk.value) {
        // 如果对话前是静音状态，则恢复静音
        isMuted.value = true;
        if (_videoController != null) {
          _videoController!.setVolume(0.0);
        }
        print('🔊 对话结束，恢复静音状态');
      } else {
        // 如果对话前是开启状态，则保持开启状态（不变）
        isMuted.value = false;
        if (_videoController != null) {
          _videoController!.setVolume(1.0);
        }
        print('🔊 对话结束，保持音量开启状态');
      }

      print('对话已结束');
    } catch (e) {
      print('停止对话错误: $e');
    }
  }

  /// 检查并请求麦克风权限 - 简化版
  Future<bool> _checkMicrophonePermission() async {
    try {
      print('🎤 检查麦克风权限...');

      // 1. 简单检查当前状态
      PermissionStatus status = await Permission.microphone.status;
      print('🎤 当前状态: $status');

      // 2. 如果已授权，直接返回
      if (status.isGranted) {
        print('🎤 权限已授权');
        return true;
      }

      // 3. 如果永久拒绝，引导到设置
      if (status.isPermanentlyDenied) {
        print('🎤 权限永久拒绝，跳转设置');
        BotToast.showText(text: '需要录音权限，请在设置中开启');
        await openAppSettings();
        return false;
      }

      // 4. 直接请求权限（不再做复杂判断）
      print('🎤 直接请求权限...');
      PermissionStatus result = await Permission.microphone.request();
      print('🎤 请求结果: $result');

      if (result.isGranted) {
        print('🎤 权限授权成功！');
        BotToast.showText(text: '录音权限已开启');
        return true;
      } else {
        print('🎤 权限被拒绝: $result');
        if (result.isPermanentlyDenied) {
          BotToast.showText(text: '需要录音权限，请在设置中开启');
          await openAppSettings();
        } else {
          BotToast.showText(text: '需要录音权限才能使用对话功能');
        }
        return false;
      }
    } catch (e) {
      print('🎤 权限检查异常: $e');
      BotToast.showText(text: '权限检查失败，请重试');
      return false;
    }
  }

  // 权限对话框已简化，直接使用 openAppSettings()

  /// 连接对话WebSocket
  Future<void> _connectTalkWebSocket(String url) async {
    try {
      _talkWebSocket = WebSocketChannel.connect(Uri.parse(url));

      // 监听WebSocket消息
      _talkWebSocket!.stream.listen(
        (data) {
          try {
            // 尝试解析JSON消息
            final message = jsonDecode(data.toString());
            print('WebSocket收到消息: $message');

            // 检查是否是状态码消息
            if (message is Map<String, dynamic>) {
              final code = message['code'] as int?;
              final messageText = message['message'] as String?;

              if (code != null) {
                print('收到状态码: $code, 消息: $messageText');

                switch (code) {
                  case 1001:
                    print('❌ 通道被占用');
                    BotToast.showText(text: '通道被占用，请稍后重试');
                    _stopTalk();
                    break;
                  case 1002:
                    print('❌ 设备对讲失败');
                    BotToast.showText(text: '设备对讲失败，请检查设备状态');
                    _stopTalk();
                    break;
                  default:
                    print('收到其他状态码: $code');
                    break;
                }
                return; // 处理完状态码后直接返回
              }
            }

            // 如果不是状态码消息，按原来的逻辑处理
            if (data is List<int>) {
              // 接收到音频数据，但不播放（视频播放器已包含音频）
              print('接收到音频数据: ${data.length} bytes（视频播放器已包含音频）');
            }
          } catch (e) {
            // 如果不是JSON格式，按原来的逻辑处理
            if (data is List<int>) {
              print('接收到音频数据: ${data.length} bytes（视频播放器已包含音频）');
            } else {
              print('收到非JSON消息: $data');
            }
          }
        },
        onError: (error) {
          print('WebSocket错误: $error');
          BotToast.showText(text: '网络环境不佳，请稍后尝试');
          _stopTalk();
        },
        onDone: () {
          print('WebSocket连接已关闭');
          if (isTalking.value) {
            _stopTalk();
          }
        },
      );

      print('WebSocket连接成功');
    } catch (e) {
      print('WebSocket连接失败: $e');
      throw Exception('连接失败');
    }
  }

  /// 开始录音（真实录音实现）
  Future<void> _startAudioRecording() async {
    try {
      // 初始化 FlutterSound 录音器
      await _flutterSoundRecorder.openRecorder();

      // 创建音频流控制器
      final audioStreamController = StreamController<Uint8List>();

      // 监听音频流并发送到 WebSocket
      audioStreamController.stream.listen((data) {
        if (_talkWebSocket != null && isTalking.value) {
          // 将PCM数据转换为Base64编码
          final base64Data = base64Encode(data);
          print('🎤 发送Base64音频数据: ${base64Data.length} chars');
          _talkWebSocket!.sink.add(base64Data);
        }
      });

      // 开始录音，使用实时流
      await _flutterSoundRecorder.startRecorder(
        toStream: audioStreamController.sink,
        codec: Codec.pcm16,
        sampleRate: 8000,
        numChannels: 1,
      );

      print('录音已开始（真实录音）');
    } catch (e) {
      print('开始录音失败: $e');
      throw Exception('录音失败');
    }
  }

  /// 停止录音
  Future<void> _stopAudioRecording() async {
    try {
      _audioTimer?.cancel();
      _audioTimer = null;
      _audioStreamSubscription?.cancel();
      _audioStreamSubscription = null;

      // 停止 FlutterSound 录音器
      await _flutterSoundRecorder.stopRecorder();
      await _flutterSoundRecorder.closeRecorder();

      print('录音已停止');
    } catch (e) {
      print('停止录音错误: $e');
    }
  }

  /// 发送音频数据（模拟）- 保留作为备用
  void _sendAudioData() async {
    try {
      if (_talkWebSocket != null && isTalking.value) {
        // 发送模拟的PCM音频数据
        final dummyPcmData = List.generate(1024, (index) => index % 256);
        _talkWebSocket!.sink.add(dummyPcmData);
      }
    } catch (e) {
      print('发送音频数据错误: $e');
    }
  }

  /// 截图功能
  Future<void> takeScreenshot() async {
    await _captureSnapshot('截图');
  }

  /// 抓拍功能
  Future<void> captureImage() async {
    await _captureSnapshot('抓拍');
  }

  /// 通用抓图方法
  Future<void> _captureSnapshot(String actionName) async {
    // ✅ 检查设备是否离线
    if (isDeviceOffline) {
      BotToast.showText(text: '设备已离线');
      return;
    }

    if (deviceId.isEmpty) {
      BotToast.showText(text: '设备信息不完整');
      return;
    }

    try {
      print('📸 开始$actionName...');
      print('📱 设备ID: $deviceId');
      print('📺 通道ID: $channelId');

      final response = await _videoService.channelSnapshot(
        serial: deviceId,
        channel: 1,
        code: channelId.isNotEmpty ? channelId : null,
        timeout: 15,
      );

      print('📊 $actionName接口响应: ${response['code']}, ${response['success']}');

      if (response['code'] == 0 && response['success'] == true) {
        final base64Data = response['data']?.toString();
        if (base64Data != null && base64Data.isNotEmpty) {
          print('📸 获取到图片数据，长度: ${base64Data.length}');

          // 保存图片到相册
          final success = await _saveBase64ImageToGallery(
            base64Data,
            actionName,
          );
          if (success) {
            BotToast.showText(text: '$actionName成功，已保存到相册');
            print('✅ $actionName成功，图片已保存到相册');
          } else {
            BotToast.showText(text: '$actionName成功，但保存到相册失败');
            print('⚠️ $actionName成功，但保存到相册失败');
          }
        } else {
          throw Exception('$actionName返回的图片数据为空');
        }
      } else {
        throw Exception(response['msg'] ?? '$actionName失败');
      }
    } catch (e) {
      print('❌ $actionName错误: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 保存Base64图片到相册
  Future<bool> _saveBase64ImageToGallery(
    String base64Data,
    String actionName,
  ) async {
    try {
      print('🔐 开始检查存储权限...');

      // 使用Gal检查权限
      final hasAccess = await Gal.hasAccess();
      if (!hasAccess) {
        print('🔑 请求存储权限...');
        final requestResult = await Gal.requestAccess();
        if (!requestResult) {
          print('❌ 存储权限被拒绝');
          BotToast.showText(text: '需要相册权限才能保存截图');
          return false;
        }
      }

      print('✅ 存储权限检查通过');
      print('🔧 开始处理Base64数据...');

      // 处理Base64数据
      String cleanBase64 = base64Data;
      // 如果包含data:image前缀，则去除
      if (cleanBase64.contains(',')) {
        cleanBase64 = cleanBase64.split(',').last;
        print('📝 已去除data URI前缀');
      }

      // 解码Base64为Uint8List
      final Uint8List imageBytes = base64Decode(cleanBase64);
      print('🖼️ Base64解码成功，图片大小: ${imageBytes.length} bytes');

      // 生成临时文件名
      final timestamp = DateTime.now().millisecondsSinceEpoch;
      final fileName = '${actionName}_$timestamp.jpg';

      // 创建临时文件
      final tempDir = Directory.systemTemp;
      final tempFile = File('${tempDir.path}/$fileName');
      await tempFile.writeAsBytes(imageBytes);
      print('📂 临时文件创建: ${tempFile.path}');

      print('💾 开始保存到相册...');

      // 使用Gal保存图片到相册
      await Gal.putImage(tempFile.path);

      // 删除临时文件
      await tempFile.delete();

      print('✅ 图片保存成功到相册');
      return true;
    } on GalException catch (e) {
      print('💥 Gal插件异常: ${e.type.message}');
      switch (e.type) {
        case GalExceptionType.accessDenied:
          BotToast.showText(text: '相册权限被拒绝');
          break;
        case GalExceptionType.notEnoughSpace:
          BotToast.showText(text: '存储空间不足');
          break;
        case GalExceptionType.notSupportedFormat:
          BotToast.showText(text: '不支持的图片格式');
          break;
        case GalExceptionType.unexpected:
          BotToast.showText(text: '网络环境不佳，请稍后尝试');
          break;
      }
      return false;
    } catch (e) {
      print('💥 保存图片到相册异常: $e');
      print('🧰 异常类型: ${e.runtimeType}');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
      return false;
    }
  }

  /// 录像功能 - 开始或停止录像
  void startRecording() {
    if (isRecording.value) {
      _stopRecording();
    } else {
      _startRecording();
    }
  }

  /// 开始录像
  Future<void> _startRecording() async {
    // ✅ 检查设备是否离线
    if (isDeviceOffline) {
      BotToast.showText(text: '设备已离线');
      return;
    }

    if (_streamUrl.value.isEmpty || !_isStreamStarted.value) {
      BotToast.showText(text: '请先开启视频流');
      return;
    }

    if (_streamId.value.isEmpty) {
      BotToast.showText(text: '获取流ID失败，请重新加载视频');
      return;
    }

    if (isStartingRecord.value || isStoppingRecord.value) return;

    isStartingRecord.value = true;
    try {
      print('开始录像，StreamID: ${_streamId.value}');

      final response = await _recordService.startRecord(
        streamId: _streamId.value,
        interval: 0, // 不分段
      );

      if (response['code'] == 0) {
        isRecording.value = true;
        BotToast.showText(text: '开始录像');
        print('录像开始成功');
      } else {
        throw Exception(response['msg'] ?? '开始录像失败');
      }
    } catch (e) {
      print('开始录像错误: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      isStartingRecord.value = false;
    }
  }

  /// 停止录像
  Future<void> _stopRecording() async {
    if (isStartingRecord.value || isStoppingRecord.value) return;

    if (_streamId.value.isEmpty) {
      BotToast.showText(text: '流ID不存在，无法停止录像');
      isRecording.value = false; // 重置状态
      return;
    }

    isStoppingRecord.value = true;
    try {
      print('停止录像，StreamID: ${_streamId.value}');

      final response = await _recordService.stopRecord(
        streamId: _streamId.value,
      );

      if (response['code'] == 0) {
        isRecording.value = false;
        BotToast.showText(text: '录像已停止');

        // 获取录像文件信息
        final recordData = response['data'];
        if (recordData != null) {
          final recordCount = recordData['RecordCount'] ?? 0;
          print('录像停止成功，共生成 $recordCount 个文件');

          if (recordCount > 0) {
            BotToast.showText(text: '录像已保存，共$recordCount个文件');

            // 🎯 自动下载录像文件
            final recordList = recordData['RecordList'] as List<dynamic>?;
            if (recordList != null && recordList.isNotEmpty) {
              print('📥 开始自动下载录像文件...');

              for (final recordItem in recordList) {
                final downloadUrl = recordItem['DownloadURL']?.toString();
                final startTimeStr = recordItem['StartTime']?.toString() ?? '';
                final endTimeStr = recordItem['EndTime']?.toString() ?? '';

                if (downloadUrl != null && downloadUrl.isNotEmpty) {
                  print('🔗 发现下载链接: $downloadUrl');
                  print('⏰ 时间范围: $startTimeStr - $endTimeStr');

                  // 调用MP4下载功能
                  await _triggerMp4Download(
                    downloadUrl: downloadUrl,
                    startTimeStr: startTimeStr,
                    endTimeStr: endTimeStr,
                  );
                }
              }
            }
          }
        }
      } else {
        throw Exception(response['msg'] ?? '停止录像失败');
      }
    } catch (e) {
      print('停止录像错误: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      isStoppingRecord.value = false;
    }
  }

  /// 触发MP4下载
  Future<void> _triggerMp4Download({
    required String downloadUrl,
    required String startTimeStr,
    required String endTimeStr,
  }) async {
    try {
      print('🎬 准备触发MP4下载...');

      // 检查并获取下载控制器
      if (!Get.isRegistered<DownloadController>()) {
        print('❌ DownloadController 未注册，尝试重新注册');
        Get.put(DownloadController(), permanent: true);
      }

      final downloadController = Get.find<DownloadController>();
      print('✅ 成功获取下载控制器');

      // 获取设备信息
      final deviceName = this.deviceName.value;
      final deviceId = _deviceId.value;
      final channelId = _channelId.value;
      final channelName = channelDetail.value?['name'] ?? '通道';

      // 转换时间格式（从YYYYMMDDHHMMSS到ISO格式）
      final startTime = _convertTimeFormat(startTimeStr);
      final endTime = _convertTimeFormat(endTimeStr);

      // 计算时长
      final duration = _calculateDuration(startTime, endTime);

      print('📊 下载参数:');
      print('  设备: $deviceName ($deviceId)');
      print('  通道: $channelName ($channelId)');
      print('  开始时间: $startTime');
      print('  结束时间: $endTime');
      print('  时长: $duration');
      print('  下载链接: $downloadUrl');

      // 获取实时截图作为封面
      String coverPicUrl = '';
      try {
        print('📸 获取实时截图作为封面...');
        final response = await _videoService.channelSnapshot(
          serial: deviceId,
          channel: 1,
          code: channelId.isNotEmpty ? channelId : null,
          timeout: 10,
        );

        if (response['code'] == 0 && response['success'] == true) {
          final base64Data = response['data']?.toString();
          if (base64Data != null && base64Data.isNotEmpty) {
            // 将Base64数据转换为Data URL格式
            coverPicUrl = '$base64Data';
            print('✅ 获取到实时截图，长度: ${base64Data.length}');
          } else {
            print('⚠️ 截图数据为空');
          }
        } else {
          print('⚠️ 获取截图失败: ${response['msg']}');
        }
      } catch (e) {
        print('⚠️ 获取截图异常: $e');
        // 继续下载，只是没有封面
      }

      // 调用MP4下载
      await downloadController.startMp4Download(
        downloadUrl: downloadUrl,
        deviceName: deviceName,
        deviceId: deviceId,
        channelId: channelId,
        channelName: channelName,
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        picUrl: coverPicUrl, // 使用实时截图作为封面
      );

      print('✅ MP4下载任务已启动');
      BotToast.showText(text: '录像下载已开始，请在下载页面查看进度');

      // 强制更新UI
      update();
    } catch (e) {
      print('❌ 触发MP4下载失败: $e');
      BotToast.showText(text: '下载启动失败，请手动重试');
    }
  }

  /// 转换时间格式（从YYYYMMDDHHMMSS到ISO格式）
  String _convertTimeFormat(String timeStr) {
    try {
      if (timeStr.length >= 14) {
        // 格式：YYYYMMDDHHMMSS
        final year = timeStr.substring(0, 4);
        final month = timeStr.substring(4, 6);
        final day = timeStr.substring(6, 8);
        final hour = timeStr.substring(8, 10);
        final minute = timeStr.substring(10, 12);
        final second = timeStr.substring(12, 14);

        return '$year-$month-${day}T$hour:$minute:$second';
      } else {
        print('⚠️ 时间格式不正确: $timeStr');
        return timeStr;
      }
    } catch (e) {
      print('⚠️ 时间格式转换失败: $e');
      return timeStr;
    }
  }

  /// 计算时长
  String _calculateDuration(String startTime, String endTime) {
    try {
      final start = DateTime.parse(startTime);
      final end = DateTime.parse(endTime);
      final duration = end.difference(start);

      final minutes = duration.inMinutes;
      final seconds = duration.inSeconds % 60;

      return "${minutes}'${seconds.toString().padLeft(2, '0')}\"";
    } catch (e) {
      print('⚠️ 时长计算失败: $e');
      return '未知';
    }
  }

  /// 云台控制 - 开始移动
  Future<void> startPTZControl(String direction) async {
    if (deviceId.isEmpty || channelId.isEmpty) {
      BotToast.showText(text: '设备信息不完整');
      return;
    }

    if (isDeviceOffline) {
      BotToast.showText(text: '设备已离线');
      return;
    }

    // 将中文方向转换为英文指令
    final command = _convertDirectionToCommand(direction);
    if (command == null) {
      BotToast.showText(text: '未支持的控制指令');
      return;
    }

    try {
      print('云台开始控制: $direction -> $command');

      final response = await _videoService.controlPTZ(
        serial: deviceId,
        code: channelId,
        command: command,
        speed: 129, // 默认速度
      );

      if (response['code'] == 0 && response['success'] == true) {
        print('云台开始控制成功: ${response['data']}');
      } else {
        throw Exception(response['msg'] ?? '云台控制失败');
      }
    } catch (e) {
      print('云台开始控制错误: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 云台控制 - 停止移动
  Future<void> stopPTZControl() async {
    if (deviceId.isEmpty || channelId.isEmpty) {
      return;
    }

    try {
      print('云台停止控制');

      final response = await _videoService.controlPTZ(
        serial: deviceId,
        code: channelId,
        command: "stop",
        speed: 129, // 默认速度
      );

      if (response['code'] == 0 && response['success'] == true) {
        print('云台停止控制成功: ${response['data']}');
      } else {
        print('云台停止控制失败: ${response['msg']}');
      }
    } catch (e) {
      print('云台停止控制错误: $e');
    }
  }

  /// 云台控制 - 兼容旧接口
  Future<void> controlPTZ(String direction) async {
    await startPTZControl(direction);
  }

  /// 将中文方向转换为英文指令
  String? _convertDirectionToCommand(String direction) {
    switch (direction) {
      case '向上':
        return 'up';
      case '向下':
        return 'down';
      case '向左':
        return 'left';
      case '向右':
        return 'right';
      case '左上':
        return 'upleft';
      case '右上':
        return 'upright';
      case '左下':
        return 'downleft';
      case '右下':
        return 'downright';
      case '放大':
      case '拉近':
        return 'zoomin';
      case '缩小':
      case '拉远':
        return 'zoomout';
      case '停止':
        return 'stop';
      default:
        return null;
    }
  }

  /// 重新加载视频
  Future<void> reloadVideo() async {
    print('🔄 开始重新加载视频');
    isLoading.value = true;
    isBuffering.value = false;
    isPlayingAlarmVideo.value = false; // 重置告警视频播放状态

    try {
      // 停止当前视频
      if (_videoController != null) {
        print('🔄 清理当前视频播放器');
        _videoController!.removeListener(_onVideoPlayerChanged);
        _videoController!.dispose();
        _videoController = null;
        isVideoInitialized.value = false;
        isPlaying.value = false;
      }

      // 清理流状态
      _streamUrl.value = '';
      _streamId.value = '';
      _isStreamStarted.value = false;

      // 减少等待时间
      await Future.delayed(const Duration(milliseconds: 200));

      // 重新开始视频流
      print('🔄 重新获取视频流');
      await _startVideoStream();

      print('✅ 视频重新加载完成');
      BotToast.showText(text: '视频已重新加载');
    } catch (e) {
      print('❌ 重新加载视频失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      isLoading.value = false;
    }
  }

  // 录像回放相关方法已移至 PlaybackController

  /// 测试视频流地址是否可访问
  Future<bool> testVideoStreamUrl(String url) async {
    try {
      print('🔍 测试视频流地址: $url');

      // 检查URL格式 - 支持所有流类型
      final isRtmp = url.startsWith('rtmp://');
      final isHls =
          url.contains('.m3u8') ||
          (url.startsWith('http') &&
              !url.contains('.flv') &&
              !url.contains('webrtc'));
      final isFlv = url.contains('.flv') || url.contains('flv');
      final isWebrtc = url.contains('webrtc') || url.startsWith('webrtc://');
      final isRtsp = url.startsWith('rtsp://');
      final isWsFlv = url.startsWith('ws://') || url.startsWith('wss://');

      if (!isRtmp && !isHls && !isFlv && !isWebrtc && !isRtsp && !isWsFlv) {
        print('❌ 不支持的流格式: $url');
        return false;
      }

      // 根据流类型显示相应的提示
      if (isRtmp) {
        print('🔍 检测到RTMP流: $url');
        print('🎬 将尝试使用RTMP播放器播放');
      } else if (isHls) {
        print('🔍 检测到HLS流: $url');
        print('🎬 将尝试使用HLS播放器播放');
      } else if (isFlv) {
        print('🔍 检测到FLV流: $url');
        print('🎬 将尝试使用FLV播放器播放');
      } else if (isWebrtc) {
        print('🔍 检测到WEBRTC流: $url');
        print('🎬 将尝试使用WEBRTC播放器播放');
      } else if (isRtsp) {
        print('🔍 检测到RTSP流: $url');
        print('🎬 将尝试使用RTSP播放器播放');
      } else if (isWsFlv) {
        print('🔍 检测到WS_FLV流: $url');
        print('🎬 将尝试使用WebSocket FLV播放器播放');
      }

      return true;
    } catch (e) {
      print('❌ 视频流地址测试失败: $e');
      return false;
    }
  }

  /// 测试RTMP流支持（已移除，直接返回true以节省时间）
  Future<bool> testRtmpSupport() async {
    // 直接返回true，fvp插件已经支持RTMP，无需测试
    print('✅ fvp插件支持RTMP，跳过测试以节省时间');
    return true;
  }

  /// 切换视频流类型（已移除，强制使用HLS）
  Future<void> switchVideoStream(String streamType) async {
    // 不再支持切换流类型，强制使用HLS
    BotToast.showText(text: '当前使用HLS流');
  }

  /// 进入全屏模式
  Future<void> enterFullscreen() async {
    try {
      // 设置横屏
      await SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);

      // 设置沉浸式模式，隐藏状态栏和导航栏
      SystemChrome.setSystemUIOverlayStyle(
        const SystemUiOverlayStyle(
          statusBarColor: Colors.transparent,
          statusBarIconBrightness: Brightness.light,
          systemNavigationBarColor: Colors.transparent,
          systemNavigationBarIconBrightness: Brightness.light,
        ),
      );

      await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);

      isFullscreen.value = true;
    } catch (e) {
      print('进入全屏失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 退出全屏模式
  Future<void> exitFullscreen() async {
    try {
      // 恢复竖屏
      await SystemChrome.setPreferredOrientations([
        DeviceOrientation.portraitUp,
      ]);

      // 显示系统UI
      await SystemChrome.setEnabledSystemUIMode(
        SystemUiMode.manual,
        overlays: SystemUiOverlay.values,
      );

      isFullscreen.value = false;
    } catch (e) {
      print('退出全屏失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 切换全屏状态
  Future<void> toggleFullscreen() async {
    if (isFullscreen.value) {
      await exitFullscreen();
    } else {
      await enterFullscreen();
    }
  }

  /// 刷新页面数据
  Future<void> refreshData() async {
    await _initializeData();
  }

  String _formatDateForDisplay(DateTime date) {
    return '${date.year}年${date.month.toString().padLeft(2, '0')}月${date.day.toString().padLeft(2, '0')}日';
  }

  /// 获取格式化的告警日期字符串
  String get formattedAlarmDate {
    return _formatDateForDisplay(selectedAlarmDate.value);
  }

  // 录像回放相关方法已移至 PlaybackController

  // ============ 告警历史相关方法 ============

  /// 加载告警历史数据
  Future<void> loadAlarmHistory({bool isRefresh = false}) async {
    print('🚀 开始加载告警历史数据，isRefresh: $isRefresh');

    if (isLoadingAlarms.value) {
      print('⏳ 告警数据正在加载中，跳过本次请求');
      return;
    }

    try {
      if (isRefresh) {
        _alarmCurrentPage = 1;
        hasMoreAlarms.value = true;
      }

      isLoadingAlarms.value = true;
      print('📊 设置告警加载状态为true');

      // 先加载未读数量（异步进行，不阻塞）
      _loadUnreadAlarmCount();

      // ✅ 检查设备参数是否有效 - 如果参数为空，直接返回，避免阻塞UI
      print(
        '🔍 检查设备参数 - deviceId: "${_deviceId.value}", hsId: "${_hsId.value}"',
      );

      // ✅ 如果参数为空，直接返回，不进行同步等待（避免阻塞UI）
      if (_deviceId.value.isEmpty && _hsId.value.isEmpty) {
        print('❌ 设备参数为空，无法加载告警历史（不等待，避免阻塞UI）');
        isLoadingAlarms.value = false;
        return;
      }

      print('✅ 设备参数检查通过');

      // ✅ 参考消息页面的逻辑：根据日期筛选状态设置时间范围
      String? startAt;
      String? endAt;

      // 设备详情页总是使用选中的日期进行筛选（类似消息页面的日期筛选）
      final selectedDate = selectedAlarmDate.value;
      final startTime = DateTime(
        selectedDate.year,
        selectedDate.month,
        selectedDate.day,
      );
      final endTime = DateTime(
        selectedDate.year,
        selectedDate.month,
        selectedDate.day,
        23,
        59,
        59,
      );

      // ✅ 转换为UTC时间，与消息页面保持一致
      final startTimeUtc = startTime.toUtc();
      final endTimeUtc = endTime.toUtc();

      // ✅ 使用与消息页面相同的格式化方法（ISO 8601格式，不含时区）
      startAt = _formatDateTimeForAlarmAPI(startTimeUtc);
      endAt = _formatDateTimeForAlarmAPI(endTimeUtc);

      print('📅 加载告警历史 - 设备ID: ${_deviceId.value}, hsId: ${_hsId.value}');
      print(
        '📅 使用日期筛选 (本地时间): ${_formatDateTimeForAlarmAPI(startTime)} ~ ${_formatDateTimeForAlarmAPI(endTime)}',
      );
      print('📅 转换为UTC时间: $startAt ~ $endAt');

      // 🌐 调用告警消息API - 参考消息页面的调用方式
      // ✅ 移除 videoType 参数（消息页面不传递也能获取到视频地址）
      // ✅ 保持 hsIds 和 deviceId 参数（设备详情页需要过滤特定设备的消息）
      final response = await _alarmService.getAlarmMessages(
        pageNo: _alarmCurrentPage,
        pageSize: _alarmPageSize,
        hsIds: _hsId.value.isNotEmpty ? [_hsId.value] : null,
        deviceId: _deviceId.value.isNotEmpty ? _deviceId.value : null,
        startTime: startAt, // ✅ 使用UTC时间格式（ISO 8601）
        endTime: endAt, // ✅ 使用UTC时间格式（ISO 8601）
        // ✅ 移除 videoType 参数，与消息页面保持一致
      );

      print('📊 告警API响应: ${response.toString()}');

      final data = response['data'] as Map<String, dynamic>?;
      if (data != null) {
        print('📊 响应data字段: ${data.toString()}');

        // 与消息页面保持一致的数据格式处理
        final records = data['records'] as List<dynamic>? ?? [];
        final total = data['total'] as int? ?? 0;
        final pages = data['pages'] as int? ?? 0;

        print('📊 解析到的records数量: ${records.length}, 总数: $total');

        // ✅ 与消息页面保持一致：转换为Map格式并使用去重逻辑
        final newAlarms = records.cast<Map<String, dynamic>>();

        if (isRefresh) {
          // ✅ 刷新时直接替换并使用去重
          final uniqueAlarms = _removeDuplicateAlarms(newAlarms);
          print(
            '🔄 刷新模式 - 新告警:${newAlarms.length}条, 去重后:${uniqueAlarms.length}条',
          );
          alarmList.value = uniqueAlarms;
          alarmList.refresh(); // ✅ 显式触发响应式更新
          print('✅ 列表更新完成 - 当前列表长度:${alarmList.length}');
        } else {
          // ✅ 加载更多时去重合并
          final combinedAlarms = [...alarmList, ...newAlarms];
          final uniqueAlarms = _removeDuplicateAlarms(combinedAlarms);
          print(
            '📚 加载更多 - 原有:${alarmList.length}条, 新增:${newAlarms.length}条, 去重后:${uniqueAlarms.length}条',
          );
          alarmList.value = uniqueAlarms;
          alarmList.refresh(); // ✅ 显式触发响应式更新
          print('✅ 列表更新完成 - 当前列表长度:${alarmList.length}');
        }

        // 检查是否还有更多数据 - 与消息页面保持一致
        hasMoreAlarms.value = _alarmCurrentPage < pages;

        print(
          '✅ 获取告警列表成功：当前页${_alarmCurrentPage}，总数$total，列表实际数量${alarmList.length}',
        );
        print('🔍 告警列表内容预览: ${alarmList.take(2).toList()}');
      } else {
        print('❌ API响应data字段为空');
      }
    } catch (e) {
      print('❌ 加载告警历史失败: $e');
      print('📝 异常堆栈: ${e.toString()}');
    } finally {
      print('🔄 重置告警加载状态');
      isLoadingAlarms.value = false;
    }
  }

  /// 定位目标告警（从消息页跳转）
  void _locateTargetAlarm() {
    if (_targetAlarmId == null || _targetAlarmId!.isEmpty) {
      print('❌ 没有目标告警ID，无法定位');
      return;
    }

    print('🔍 开始定位告警，目标ID: $_targetAlarmId');
    print('📊 当前告警列表长度: ${alarmList.length}');

    // 查找目标告警在列表中的索引
    final targetIndex = alarmList.indexWhere(
      (alarm) => alarm['id']?.toString() == _targetAlarmId,
    );

    if (targetIndex >= 0) {
      print('✅ 找到目标告警，索引: $targetIndex');
      // 选中该告警
      selectedAlarmIndex.value = targetIndex;

      // 触发UI更新并等待渲染
      Future.delayed(const Duration(milliseconds: 300), () {
        // 通知AlarmHistoryWidget滚动到指定位置
        // 使用GetX的update机制触发滚动
        Get.find<DeviceDetailController>().update(['alarm_scroll']);
        print('📍 已触发滚动到告警索引: $targetIndex');
      });
    } else {
      print('❌ 未找到目标告警ID: $_targetAlarmId');
      print('📋 告警列表ID列表: ${alarmList.map((a) => a['id']).toList()}');

      // 如果还有更多数据，继续加载
      if (hasMoreAlarms.value) {
        print('📥 继续加载更多告警数据...');
        loadMoreAlarmHistory().then((_) {
          _locateTargetAlarm(); // 递归查找
        });
      }
    }
  }

  /// 加载更多告警历史
  Future<void> loadMoreAlarmHistory() async {
    if (!hasMoreAlarms.value || isLoadingAlarms.value) return;

    _alarmCurrentPage++;
    await loadAlarmHistory(isRefresh: false);
  }

  /// 刷新告警历史
  Future<void> refreshAlarmHistory() async {
    await loadAlarmHistory(isRefresh: true);
  }

  /// 选择告警日期
  Future<void> selectAlarmDate(DateTime date) async {
    selectedAlarmDate.value = date;
    print('📅 选择告警日期: ${date.toString()}');

    // 重新加载该日期的告警数据
    await loadAlarmHistory(isRefresh: true);

    // 重新加载该日期的未读数量
    _loadUnreadAlarmCount();

    // ✅ 切换日期后，自动播放第一条告警视频
    // loadAlarmHistory 完成后，isLoadingAlarms 应该已经是 false
    if (alarmList.isNotEmpty) {
      print('📅 日期切换完成，找到 ${alarmList.length} 条告警，自动播放第一条');
      await _autoPlayLatestAlarm();
    } else {
      print('📅 日期切换完成，该日期无告警记录，显示提示');
      // 停止当前视频并显示"暂无告警视频"提示
      stopCurrentVideoAndShowNoAlarmVideo();
    }
  }

  /// 加载未读告警数量
  /// ✅ 统一逻辑：与消息页面保持一致，只在有日期筛选时才传时间范围
  Future<void> _loadUnreadAlarmCount() async {
    try {
      print('📊 加载未读告警数量 - 设备ID: ${_deviceId.value}');

      // ✅ 统一逻辑：设备详情页面总是使用选中日期的时间范围（类似消息页面的日期筛选）
      // 格式化当前选择日期的时间范围（当天的00:00:00到23:59:59）
      final selectedDate = selectedAlarmDate.value;
      final startTime = DateTime(
        selectedDate.year,
        selectedDate.month,
        selectedDate.day,
      );
      final endTime = DateTime(
        selectedDate.year,
        selectedDate.month,
        selectedDate.day,
        23,
        59,
        59,
      );

      // ✅ 修复：后端接口期望本地时间，不转换为UTC时间
      // 使用未读消息数接口要求的格式：YYYY-MM-DD HH:mm:ss（空格分隔，不是T）
      final startAt = _formatDateTimeForUnreadAPI(startTime);
      final endAt = _formatDateTimeForUnreadAPI(endTime);

      print('📅 未读数查询使用日期筛选 (本地时间): $startAt ~ $endAt');

      // ✅ 统一传递deviceId和时间范围，与消息页面逻辑保持一致
      final response = await _alarmService.getUnreadAlarmCount(
        deviceId: _deviceId.value.isNotEmpty ? _deviceId.value : null,
        startAt: startAt,
        endAt: endAt,
      );

      print('📊 未读数量API响应: ${response.toString()}');

      final data = response['data'] as int?;
      if (data != null) {
        unreadAlarmCount.value = data;
        print(
          '✅ 未读告警数量: $data (设备ID: ${_deviceId.value}, 时间范围: $startAt ~ $endAt)',
        );
      } else {
        print('❌ 未读数量data字段为空');
        unreadAlarmCount.value = 0;
      }
    } catch (e) {
      print('❌ 加载未读告警数量失败: $e');
      unreadAlarmCount.value = 0; // 出错时设为0
    }
  }

  /// 去除重复告警（根据告警ID去重）- 参考消息页面的逻辑
  List<Map<String, dynamic>> _removeDuplicateAlarms(
    List<Map<String, dynamic>> alarms,
  ) {
    final seenIds = <String>{};
    final uniqueAlarms = <Map<String, dynamic>>[];

    for (final alarm in alarms) {
      final id = alarm['id']?.toString();
      if (id != null && !seenIds.contains(id)) {
        seenIds.add(id);
        uniqueAlarms.add(alarm);
      }
    }

    return uniqueAlarms;
  }

  /// 格式化时间为告警API需要的格式（ISO 8601: YYYY-MM-DDTHH:mm:ss）
  /// ✅ 与消息页面保持一致，使用 'T' 分隔日期和时间
  String _formatDateTimeForAlarmAPI(DateTime dateTime) {
    return '${dateTime.year.toString().padLeft(4, '0')}-'
        '${dateTime.month.toString().padLeft(2, '0')}-'
        '${dateTime.day.toString().padLeft(2, '0')}T'
        '${dateTime.hour.toString().padLeft(2, '0')}:'
        '${dateTime.minute.toString().padLeft(2, '0')}:'
        '${dateTime.second.toString().padLeft(2, '0')}';
  }

  /// 格式化日期时间为未读消息数API需要的格式（YYYY-MM-DD HH:mm:ss，空格分隔）
  String _formatDateTimeForUnreadAPI(DateTime dateTime) {
    return '${dateTime.year.toString().padLeft(4, '0')}-'
        '${dateTime.month.toString().padLeft(2, '0')}-'
        '${dateTime.day.toString().padLeft(2, '0')} '
        '${dateTime.hour.toString().padLeft(2, '0')}:'
        '${dateTime.minute.toString().padLeft(2, '0')}:'
        '${dateTime.second.toString().padLeft(2, '0')}';
  }

  /// 标记告警消息已读
  Future<void> markAlarmRead(String msgId) async {
    try {
      await _alarmService.markAlarmMessageRead(
        msgId: msgId,
        hsId: _hsId.value,
        deviceId: _deviceId.value, // 传递设备ID
      );

      // 更新本地状态：将对应消息标记为已读
      final index = alarmList.indexWhere(
        (alarm) => alarm['id']?.toString() == msgId,
      );
      if (index >= 0) {
        final wasUnread =
            alarmList[index]['read'] != true &&
            alarmList[index]['readStatus'] != 1;

        alarmList[index]['readStatus'] = 1; // 假设1表示已读
        alarmList[index]['read'] = true; // 同时更新read字段
        alarmList.refresh(); // 触发UI更新

        // 如果这个消息之前是未读的，就减少未读数量
        if (wasUnread && unreadAlarmCount.value > 0) {
          unreadAlarmCount.value = unreadAlarmCount.value - 1;
          print('本地更新：未读数量减1，当前未读数: ${unreadAlarmCount.value}');
        }
      }

      // ✅ 同步更新消息页面的未读数量和消息状态
      try {
        // 重新加载未读告警数量以确保数据准确（使用相同的时间范围逻辑）
        await _loadUnreadAlarmCount();

        // 如果MessageController已注册，同步更新消息列表状态和未读数量
        if (Get.isRegistered<MessageController>()) {
          try {
            final messageController = Get.find<MessageController>();

            // ✅ 先刷新未读数量接口（从服务器获取最新数据）
            await messageController.refreshUnreadCount();

            // ✅ 刷新消息列表接口（确保数据同步）
            // 这会调用未读消息列表接口和告警消息列表接口（根据当前tab）
            // 接口返回的数据会反映最新的已读状态
            await messageController.refreshMessageList();

            print('✅ 已刷新消息页面的未读数量接口和消息列表接口');
          } catch (e) {
            print('⚠️ 更新MessageController状态失败: $e');
          }
        } else {
          print('⚠️ MessageController未注册，跳过同步更新');
        }

        // 刷新首页未读消息数
        if (Get.isRegistered<HomeController>()) {
          try {
            final homeController = Get.find<HomeController>();
            await homeController.refreshUnreadCount();
          } catch (e) {
            print('⚠️ 更新HomeController未读数量失败: $e');
          }
        }
      } catch (e) {
        print('⚠️ 同步更新未读数量失败: $e');
      }

      print('标记告警消息已读: $msgId');
    } catch (e) {
      print('标记告警消息已读失败: $e');
      BotToast.showText(text: '操作失败，请稍后尝试');

      // 失败时重新加载未读数量以确保数据准确
      await _loadUnreadAlarmCount();
    }
  }

  /// 一键已读所有告警
  Future<void> markAllAlarmsRead() async {
    try {
      // ✅ 传递当前选中日期的 readDay 参数
      final date = selectedAlarmDate.value;
      final readDay =
          '${date.year.toString().padLeft(4, '0')}-'
          '${date.month.toString().padLeft(2, '0')}-'
          '${date.day.toString().padLeft(2, '0')}';
      print('📅 一键已读告警，readDay: $readDay, deviceId: ${_deviceId.value}');

      // ✅ 统一传递deviceId参数，确保只标记当前设备的消息为已读
      await _alarmService.markAllMessagesRead(
        readDay: readDay,
        deviceId: _deviceId.value.isNotEmpty ? _deviceId.value : null,
      );

      // 更新本地状态：将所有消息标记为已读
      for (var alarm in alarmList) {
        alarm['readStatus'] = 1; // 假设1表示已读
        alarm['read'] = true; // 同时更新read字段
      }
      alarmList.refresh(); // 触发UI更新

      // 将未读数量直接设置为0（因为已经一键已读）
      unreadAlarmCount.value = 0;

      // ✅ 同步更新消息页面的未读数量和消息状态
      try {
        // 重新加载未读告警数量以确保数据准确（使用相同的时间范围逻辑）
        await _loadUnreadAlarmCount();

        // 如果MessageController已注册，同步清除消息页面的相关状态
        if (Get.isRegistered<MessageController>()) {
          try {
            final messageController = Get.find<MessageController>();

            // ✅ 先刷新未读数量接口（从服务器获取最新数据）
            await messageController.refreshUnreadCount();

            // ✅ 刷新消息列表接口（确保数据同步）
            // 这会调用未读消息列表接口和告警消息列表接口（根据当前tab）
            // 接口返回的数据会反映最新的已读状态
            await messageController.refreshMessageList();

            print('✅ 已刷新消息页面的未读数量接口和消息列表接口');
          } catch (e) {
            print('⚠️ 更新MessageController状态失败: $e');
          }
        } else {
          print('⚠️ MessageController未注册，跳过同步更新');
        }

        // 刷新首页未读消息数
        if (Get.isRegistered<HomeController>()) {
          try {
            final homeController = Get.find<HomeController>();
            await homeController.refreshUnreadCount();
          } catch (e) {
            print('⚠️ 更新HomeController未读数量失败: $e');
          }
        }
      } catch (e) {
        print('⚠️ 同步更新未读数量失败: $e');
      }

      BotToast.showText(text: '已全部标记为已读');
      print('一键已读所有告警成功，未读数量已清零');
    } catch (e) {
      print('一键已读所有告警失败: $e');
      BotToast.showText(text: '操作失败，请稍后尝试');

      // 失败时重新加载未读数量以确保数据准确
      await _loadUnreadAlarmCount();
    }
  }

  // ============ 录像回放相关方法 ============

  /// 选择录像回放时间
  void selectPlaybackTime(DateTime time) {
    selectedPlaybackTime.value = time;
    showNoRecordMessage.value = false; // 重置"暂无录像"提示

    // 检查该时间是否有录像
    final hasRecord = _hasRecordAtTime(time);
    if (hasRecord) {
      // BotToast.showText(text: '播放录像: $timeStr');
      _loadPlaybackVideo(time);
    }
    // else {
    //   BotToast.showText(text: '选择时间: $timeStr (无录像)');
    // }
  }

  /// 计算选中时间相对于片段开始时间的偏移秒数
  int _calculateOffsetSeconds(
    DateTime selectedTime,
    DateTime segmentStartTime,
  ) {
    final offset = selectedTime.difference(segmentStartTime);
    final offsetSeconds = offset.inSeconds;
    print(
      '⏱️ 计算偏移秒数: 选中时间=$selectedTime, 片段开始时间=$segmentStartTime, 偏移=$offsetSeconds秒',
    );
    return offsetSeconds > 0 ? offsetSeconds : 0;
  }

  /// 检查指定时间是否有录像
  bool _hasRecordAtTime(DateTime time) {
    // 根据当前录像源类型选择对应的数据列表
    final segments =
        recordSourceType.value == 'cloud'
            ? recordSegments
            : localRecordSegments;

    for (final segment in segments) {
      final startTime = segment['startTime'] as DateTime?;
      final endTime = segment['endTime'] as DateTime?;
      if (startTime != null && endTime != null) {
        if (time.isAfter(startTime) && time.isBefore(endTime)) {
          return true;
        }
      }
    }
    return false;
  }

  /// 加载指定日期的录像列表
  Future<void> loadRecordsForDate([DateTime? targetDate]) async {
    final date = targetDate ?? selectedPlaybackDate.value;
    // 确保日期只包含年月日
    final normalizedDate = DateTime(date.year, date.month, date.day);

    print('🎬 开始加载录像数据 - 日期: ${_formatDateForAPI(normalizedDate)}');
    print('🎬 设备ID: ${_deviceId.value}, 通道ID: ${_channelId.value}');
    print('🎬 录像源类型: ${recordSourceType.value}');

    isLoadingRecords.value = true;

    try {
      // 清空当前数据
      recordSegments.clear();
      localRecordSegments.clear();
      selectedRecordIds.clear();
      isAllSelected.value = false;

      // 使用录像数据管理器加载数据
      final segments = await _recordDataManager.loadRecordData(
        deviceId: _deviceId.value,
        channelId: _channelId.value,
        date: normalizedDate,
        sourceType: recordSourceType.value,
      );

      // 将标准化的数据转换为Map格式，保持与现有代码的兼容性
      final formattedRecords =
          segments.map((segment) => segment.toMap()).toList();

      if (recordSourceType.value == 'cloud') {
        recordSegments.addAll(formattedRecords);
      } else {
        localRecordSegments.addAll(formattedRecords);
      }

      print('✅ 录像数据加载完成，共 ${segments.length} 条记录');
    } catch (e) {
      print('❌ 加载录像列表异常: $e');
      BotToast.showText(text: '加载录像数据失败，请稍后重试');
      // 异常时也清空数据
      recordSegments.clear();
      localRecordSegments.clear();
      selectedRecordIds.clear();
      isAllSelected.value = false;
    } finally {
      isLoadingRecords.value = false;
      print('🔄 录像数据加载完成，状态重置');
    }
  }

  /// 格式化日期为API格式 (YYYYMMDD)
  String _formatDateForAPI(DateTime date) {
    return '${date.year}${date.month.toString().padLeft(2, '0')}${date.day.toString().padLeft(2, '0')}';
  }

  String _formatDateTimeForAPI(DateTime date) {
    return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}T${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}:${date.second.toString().padLeft(2, '0')}';
  }

  /// 加载回放视频
  Future<void> _loadPlaybackVideo(DateTime time) async {
    // 防抖：如果正在加载，直接返回
    if (isLoadingPlayback.value) {
      print('⏳ 回放视频正在加载中，跳过重复请求');
      return;
    }

    isLoadingPlayback.value = true; // 设置加载标志
    showNoRecordMessage.value = false; // 重置"暂无录像"提示
    print('🔄 _loadPlaybackVideo: 重置showNoRecordMessage为false');

    try {
      print('🎬 开始加载回放视频，时间: $time');

      // 根据当前录像源类型选择对应的数据列表
      final segments =
          recordSourceType.value == 'cloud'
              ? recordSegments
              : localRecordSegments;

      print('📊 录像源类型: ${recordSourceType.value}, 片段数量: ${segments.length}');

      // 找到包含该时间的录像片段
      Map<String, dynamic>? targetSegment;
      for (final segment in segments) {
        final startTime = segment['startTime'] as DateTime?;
        final endTime = segment['endTime'] as DateTime?;
        if (startTime != null && endTime != null) {
          if (time.isAfter(startTime) && time.isBefore(endTime)) {
            targetSegment = segment;
            break;
          }
        }
      }

      if (targetSegment == null) {
        print('📋 当前时间无录像，尝试播放最后一条录像');

        // 如果当前时间没有录像，播放最后一条录像
        if (segments.isNotEmpty) {
          // 按开始时间排序，取最后一个（最新的）
          final sortedSegments = List<Map<String, dynamic>>.from(segments);
          sortedSegments.sort((a, b) {
            final startTimeA = a['startTime'] as DateTime?;
            final startTimeB = b['startTime'] as DateTime?;
            if (startTimeA == null || startTimeB == null) return 0;
            return startTimeA.compareTo(startTimeB);
          });

          targetSegment = sortedSegments.last;
          print(
            '🎬 找到最后一条录像: ${targetSegment['startTime']} - ${targetSegment['endTime']}',
          );

          // 更新播放时间为该片段的开始时间（但不触发UI更新，避免调用stopCurrentVideo）
          final segmentStartTime = targetSegment['startTime'] as DateTime?;
          if (segmentStartTime != null) {
            // 直接设置值，不触发响应式更新
            selectedPlaybackTime.value = segmentStartTime;
            print('🎬 更新播放时间为: ${segmentStartTime}');
          }
        } else {
          print('❌ 该时间段无录像片段');
          BotToast.showText(text: '该时间段无录像');
          return;
        }
      }

      print('🎯 目标录像片段: ${targetSegment}');

      // ✅ 计算选中时间相对于片段开始时间的偏移秒数
      final segmentStartTime = targetSegment['startTime'] as DateTime?;
      int? seekOffsetSeconds;
      if (segmentStartTime != null) {
        seekOffsetSeconds = _calculateOffsetSeconds(time, segmentStartTime);
      }

      if (targetSegment["source"] == "local") {
        print('🔄 本地录像回放流程开始');
        BotToast.showLoading();

        try {
          final response = await _playbackService.startPlayback(
            serial: _deviceId.value,
            starttime: _formatDateTimeForAPI(targetSegment['startTime']),
            endtime: _formatDateTimeForAPI(targetSegment['endTime']),
          );
          BotToast.closeAllLoading();

          print('📡 回放接口响应: $response');

          final data = response?["data"] ?? {};
          final flv = data?["FLV"] ?? '';

          if (flv != null && flv.isNotEmpty) {
            print('✅ 获取到本地录像FLV地址: $flv');

            // 先停止当前视频，避免资源冲突
            if (_videoController != null) {
              print('🔄 停止当前视频播放器');
              _videoController!.removeListener(_onVideoPlayerChanged);
              _videoController!.dispose();
              _videoController = null;
              isVideoInitialized.value = false;
              isPlaying.value = false;
              await Future.delayed(const Duration(milliseconds: 500));
            }

            await playAlarmVideo(flv, seekOffsetSeconds: seekOffsetSeconds);
            isPlayingRecord.value = true;
            print('✅ 本地录像开始播放');
          } else {
            print('❌ 本地录像FLV地址为空');
            BotToast.showText(text: '设备繁忙，请稍后重试');
          }
        } catch (e) {
          BotToast.closeAllLoading();
          print('❌ 本地录像回放失败: $e');
          BotToast.showText(text: '录像回放失败，请稍后重试');
        }
      } else {
        print('🔄 云端录像回放流程开始');
        final playUrl = targetSegment['playUrl'] as String?;

        if (playUrl != null && playUrl.isNotEmpty) {
          print('✅ 获取到云端录像URL: $playUrl');

          // 先停止当前视频，避免资源冲突
          if (_videoController != null) {
            print('🔄 停止当前视频播放器');
            _videoController!.removeListener(_onVideoPlayerChanged);
            _videoController!.dispose();
            _videoController = null;
            isVideoInitialized.value = false;
            isPlaying.value = false;
            await Future.delayed(const Duration(milliseconds: 500));
          }

          await playAlarmVideo(playUrl, seekOffsetSeconds: seekOffsetSeconds);
          isPlayingRecord.value = true;
          print('✅ 云端录像开始播放');
        } else {
          print('❌ 云端录像播放地址为空');
          BotToast.showText(text: '该录像片段无播放地址');
        }
      }
    } catch (e) {
      print('❌ 加载回放视频异常: $e');
      BotToast.showText(text: '录像加载失败，请稍后重试');
    } finally {
      // 延迟重置加载标志，防止过快重复请求
      Future.delayed(const Duration(seconds: 2), () {
        isLoadingPlayback.value = false;
        print('🔄 回放加载标志已重置');
      });
    }
  }

  /// 选择录像日期
  Future<void> selectPlaybackDate(DateTime date) async {
    // 只保留年月日，忽略时分秒
    final selectedDate = DateTime(date.year, date.month, date.day);
    selectedPlaybackDate.value = selectedDate;
    print('选择录像日期: ${_formatDateForDisplay(selectedDate)}');

    // ✅ 如果正在播放录像回放，先停止当前视频
    if (isPlayingRecord.value && isVideoInitialized.value) {
      print('🔄 切换日期，停止当前播放的录像');
      // 停止当前视频播放
      if (_videoController != null) {
        try {
          _videoController!.removeListener(_onVideoPlayerChanged);
          await _videoController!.pause();
          await _videoController!.dispose();
          _videoController = null;
        } catch (e) {
          print('⚠️ 停止视频播放器时出错: $e');
        }
      }
      // 重置播放状态
      isVideoInitialized.value = false;
      isPlaying.value = false;
      isPlayingRecord.value = false;
      isBuffering.value = false;
      showNoRecordMessage.value = false;
    }

    // 重新加载该日期的录像
    await loadRecordsForDate(selectedDate);

    // ✅ 数据加载完成后，如果有录像数据，自动播放最新录像
    final segments =
        recordSourceType.value == 'cloud'
            ? recordSegments
            : localRecordSegments;

    if (segments.isNotEmpty) {
      print('📋 新日期录像数据已加载，准备自动播放最新录像');
      // 等待一小段时间确保UI更新完成
      await Future.delayed(const Duration(milliseconds: 300));
      _autoPlayLatestRecord();
    } else {
      print('📋 新日期录像列表为空，显示无录像提示');
      showNoRecordMessage.value = true;
    }
  }

  /// 获取格式化的选择日期字符串
  String get formattedSelectedDate {
    return _formatDateForDisplay(selectedPlaybackDate.value);
  }

  /// 切换录像源类型
  Future<void> switchRecordSource(String sourceType) async {
    if (recordSourceType.value == sourceType) return;

    recordSourceType.value = sourceType;
    print('🔄 切换录像源到: ${sourceType == "cloud" ? "云端" : "本地"}');

    // ✅ 停止当前正在播放的视频（如果有）
    if (isVideoInitialized.value && isPlayingRecord.value) {
      print('⏹️ 停止当前播放的录像');
      _stopAllVideoAsync();
      // 等待一小段时间确保状态重置完成
      await Future.delayed(const Duration(milliseconds: 200));
    }

    // 清空当前选择状态
    selectedRecordIds.clear();
    isAllSelected.value = false;

    // 重新加载当前日期的录像数据
    await loadRecordsForDate(selectedPlaybackDate.value);

    // ✅ 数据加载完成后，如果有录像数据，自动播放最新录像
    final segments =
        recordSourceType.value == 'cloud'
            ? recordSegments
            : localRecordSegments;

    if (segments.isNotEmpty) {
      print('📋 录像源切换完成，找到 ${segments.length} 条录像，准备自动播放最新录像');
      // 等待一小段时间确保UI更新和状态重置完成
      await Future.delayed(const Duration(milliseconds: 300));
      await _autoPlayLatestRecord();
    } else {
      print('📋 录像源切换完成，该录像源无录像数据，显示无录像提示');
      showNoRecordMessage.value = true;
      // 确保视频已停止
      if (isVideoInitialized.value || isPlayingRecord.value) {
        _stopAllVideoAsync();
      }
    }

    BotToast.showText(text: sourceType == 'cloud' ? '已切换到云端录像' : '已切换到本地录像');
  }

  /// 重置录像数据加载状态
  void _resetRecordLoadingState() {
    recordSegments.clear();
    localRecordSegments.clear();
    selectedRecordIds.clear();
    isAllSelected.value = false;
    isLoadingRecords.value = false;
  }

  /// 切换全选状态
  void toggleSelectAll() {
    if (isAllSelected.value) {
      // 取消全选
      selectedRecordIds.clear();
      isAllSelected.value = false;
    } else {
      // 全选
      selectedRecordIds.clear();
      for (final segment in localRecordSegments) {
        final id = segment['id']?.toString() ?? '';
        if (id.isNotEmpty) {
          selectedRecordIds.add(id);
        }
      }
      isAllSelected.value = true;
    }
  }

  /// 切换单个录像片段的选择状态
  void toggleRecordSelection(String recordId) {
    if (selectedRecordIds.contains(recordId)) {
      selectedRecordIds.remove(recordId);
    } else {
      selectedRecordIds.add(recordId);
    }

    // 更新全选状态
    isAllSelected.value =
        selectedRecordIds.length == localRecordSegments.length;
  }

  /// 取消所有选择
  void cancelAllSelection() {
    selectedRecordIds.clear();
    isAllSelected.value = false;
  }

  /// 下载选中的录像
  Future<void> downloadSelectedRecords() async {
    if (selectedRecordIds.isEmpty) {
      BotToast.showText(text: '请先选择要下载的录像');
      return;
    }

    try {
      BotToast.showText(text: '开始下载录像...');
      // 这里可以调用下载API
      print('下载录像: ${selectedRecordIds.join(', ')}');
    } catch (e) {
      print('下载录像失败: $e');
      BotToast.showText(text: '下载失败，请稍后重试');
    }
  }

  /// 下载单个录像
  Future<void> downloadRecord(Map<String, dynamic> record) async {
    try {
      final recordId = record['id']?.toString() ?? '';
      BotToast.showText(text: '开始下载录像...');
      print('下载录像: $recordId');
      // 这里可以调用下载API
    } catch (e) {
      print('下载录像失败: $e');
      BotToast.showText(text: '下载失败，请稍后重试');
    }
  }

  /// 切换下载模式
  void toggleDownloadMode() {
    isDownloadMode.value = !isDownloadMode.value;
    print('切换下载模式: ${isDownloadMode.value ? "开启" : "关闭"}');
  }

  /// 处理录像下载
  Future<void> handleRecordDownload(Map<String, dynamic> record) async {
    try {
      // "source" -> "local"

      // 获取播放地址
      final playUrl = record['playUrl'] as String?;
      // if (playUrl == null || playUrl.isEmpty) {
      //   BotToast.showText(text: '该录像片段无播放地址');
      //   return;
      // }

      // 获取设备信息
      final deviceName = this.deviceName.value;
      final deviceId = _deviceId.value;
      final channelId = _channelId.value;
      final channelName = channelDetail.value?['name'] ?? '通道';

      // 获取时间信息
      final startTime = record['startTime'] as DateTime?;
      final endTime = record['endTime'] as DateTime?;
      final duration = record['duration'] as String? ?? '';

      if (startTime == null || endTime == null) {
        BotToast.showText(text: '录像时间信息不完整');
        return;
      }

      // 格式化时间 - 使用ISO格式
      final startTimeStr =
          '${startTime.year}-${startTime.month.toString().padLeft(2, '0')}-${startTime.day.toString().padLeft(2, '0')}T${startTime.hour.toString().padLeft(2, '0')}:${startTime.minute.toString().padLeft(2, '0')}:00';
      final endTimeStr =
          '${endTime.year}-${endTime.month.toString().padLeft(2, '0')}-${endTime.day.toString().padLeft(2, '0')}T${endTime.hour.toString().padLeft(2, '0')}:${endTime.minute.toString().padLeft(2, '0')}:00';

      if (record["source"] == "local") {
        try {
          print('🚀 开始本地录像下载流程...');

          // 第一步：调用下载接口获取WebSocket地址
          final response = await _playbackService.downloadRecord(
            deviceId: _deviceId.value,
            channelId: _channelId.value,
            storeType: 1,
            startTime: startTimeStr,
            endTime: endTimeStr,
          );

          print('📡 下载接口响应: $response');

          if (response['code'] == 0 && response['success'] == true) {
            final wsUrl = response['data'] as String?;
            if (wsUrl != null && wsUrl.isNotEmpty) {
              print('🔗 WebSocket地址: $wsUrl');

              // 第二步：连接WebSocket并处理下载流程
              await _handleWebSocketDownload(
                wsUrl: wsUrl,
                deviceId: deviceId,
                channelId: channelId,
                startTime: startTimeStr,
                endTime: endTimeStr,
                deviceName: deviceName,
                channelName: channelName,
                duration: duration,
                playUrl: playUrl ?? "",
                picUrl: record["picUrl"] ?? "",
              );
            } else {
              throw Exception('WebSocket地址为空');
            }
          } else {
            throw Exception(response['msg'] ?? '下载接口调用失败');
          }
        } catch (e) {
          print('❌ 本地录像下载失败: $e');

          // 根据错误类型显示不同的提示
          final errorMessage = e.toString().toLowerCase();
          if (errorMessage.contains('handshake') ||
              errorMessage.contains('ssl')) {
            BotToast.showText(text: '服务器证书验证失败，请联系技术支持');
          } else if (errorMessage.contains('timeout')) {
            BotToast.showText(text: '请求超时，请检查网络连接');
          } else if (errorMessage.contains('connection')) {
            BotToast.showText(text: '网络连接异常，请稍后重试');
          } else {
            BotToast.showText(text: '网络环境不佳，请稍后尝试');
          }
        }
      } else {
        if (playUrl == null || playUrl.isEmpty) {
          BotToast.showText(text: '该录像片段无播放地址');
          return;
        }
        // 云端录像直接使用playUrl
        // 显示确认弹窗
        final confirmed = await _showDownloadConfirmDialog(
          deviceName: deviceName,
          startTime: startTimeStr,
          endTime: endTimeStr,
          duration: duration,
        );

        if (confirmed) {
          await _startCloudDownload(
            picUrl: record['picUrl'] as String? ?? '',
            playUrl: playUrl,
            deviceName: deviceName,
            deviceId: deviceId,
            channelId: channelId,
            channelName: channelName,
            startTime: startTimeStr,
            endTime: endTimeStr,
            duration: duration,
          );
        }
      }
    } catch (e) {
      print('❌ 处理录像下载失败: $e');
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    }
  }

  /// 处理WebSocket下载流程
  Future<void> _handleWebSocketDownload({
    required String wsUrl,
    required String deviceId,
    required String channelId,
    required String startTime,
    required String endTime,
    required String deviceName,
    required String channelName,
    required String duration,
    required String playUrl,
    required String picUrl,
  }) async {
    WebSocketChannel? wsChannel;
    int? downloadRecordId; // 保存下载记录ID

    try {
      print('🔗 连接WebSocket: $wsUrl');

      // 检查并获取下载控制器
      if (!Get.isRegistered<DownloadController>()) {
        Get.put(DownloadController(), permanent: true);
      }
      final downloadController = Get.find<DownloadController>();

      // 转换时间格式（从YYYYMMDDHHMMSS到ISO格式，用于保存到数据库）
      // 注意：WebSocket查询参数使用原始格式（startTime, endTime），但数据库需要ISO格式
      final startTimeISO = _convertTimeFormat(startTime);
      final endTimeISO = _convertTimeFormat(endTime);

      // 在WebSocket连接开始时，立即创建下载记录（状态为等待中）
      // 这样用户可以在下载页面立即看到下载项
      downloadRecordId = await _createWaitingDownloadRecord(
        downloadController: downloadController,
        deviceName: deviceName,
        deviceId: deviceId,
        channelId: channelId,
        channelName: channelName,
        startTime: startTimeISO,
        endTime: endTimeISO,
        duration: duration,
        picUrl: picUrl,
      );

      // 构建带查询参数的WebSocket URL
      final uri = Uri.parse(wsUrl);
      final queryParameters = {
        'serial': deviceId,
        'code': channelId,
        'starttime': startTime,
        'endtime': endTime,
        'timeout': '15',
      };

      final wsUri = uri.replace(queryParameters: queryParameters);
      print('🔗 完整WebSocket URL: $wsUri');

      // 连接WebSocket
      wsChannel = WebSocketChannel.connect(wsUri);

      // 监听WebSocket响应
      await for (final message in wsChannel.stream) {
        try {
          final response = jsonDecode(message.toString());
          print('📥 WebSocket响应: $response');

          final status = response['status'] as String?;
          final messageText = response['message'] as String?;
          final data = response['data'] as Map<String, dynamic>?;

          if (status == 'success') {
            print('✅ 下载任务已启动');
            // 更新状态为"正在连接服务器资源"
            if (downloadRecordId != null) {
              await _updateWebSocketProgress(
                downloadController: downloadController,
                recordId: downloadRecordId,
                progress: 0,
              );
            }
          } else if (status == 'download') {
            // 实时更新WebSocket进度
            final progress = data?['progress'] as int? ?? 0;
            print('⏳ 流媒体处理中... 进度: $progress%');
            if (downloadRecordId != null) {
              await _updateWebSocketProgress(
                downloadController: downloadController,
                recordId: downloadRecordId,
                progress: progress,
              );
            }
          } else if (status == 'finish') {
            print('🎯 流媒体处理完成，可以下载');

            final downloadUrl = data?['url'] as String?;

            if (downloadUrl != null && downloadUrl.isNotEmpty) {
              print('🔗 获取到下载链接: $downloadUrl');

              // 关闭WebSocket连接
              wsChannel.sink.close();

              // 更新下载记录并开始下载
              if (downloadRecordId != null) {
                unawaited(
                  _updateAndStartDownload(
                    downloadController: downloadController,
                    recordId: downloadRecordId,
                    downloadUrl: downloadUrl,
                    deviceName: deviceName,
                    deviceId: deviceId,
                    channelId: channelId,
                    channelName: channelName,
                    startTime: startTimeISO,
                    endTime: endTimeISO,
                    duration: duration,
                    picUrl: picUrl,
                  ),
                );
              } else {
                // 如果记录ID不存在，使用原来的方式创建新记录
                unawaited(
                  _startLocalDownload(
                    downloadUrl: downloadUrl,
                    deviceName: deviceName,
                    deviceId: deviceId,
                    channelId: channelId,
                    channelName: channelName,
                    startTime: startTime,
                    endTime: endTime,
                    duration: duration,
                    picUrl: picUrl,
                  ),
                );
              }

              return; // WebSocket流程完成，下载在后台进行
            } else {
              throw Exception('下载链接为空');
            }
          } else if (status == 'error') {
            final errorMsg = messageText ?? '下载处理失败';
            print('❌ WebSocket错误: $errorMsg');
            // 更新下载记录状态为失败
            if (downloadRecordId != null) {
              await _updateDownloadRecordStatus(
                downloadController: downloadController,
                recordId: downloadRecordId,
                status: DownloadStatus.failed,
                errorMessage: errorMsg,
              );
            }
            BotToast.showText(text: '录像处理失败: $errorMsg');
            throw Exception(errorMsg);
          }
        } catch (e) {
          print('❌ WebSocket消息解析失败: $e');
          // 更新下载记录状态为失败
          if (downloadRecordId != null) {
            await _updateDownloadRecordStatus(
              downloadController: downloadController,
              recordId: downloadRecordId,
              status: DownloadStatus.failed,
              errorMessage: 'WebSocket通信异常',
            );
          }
          BotToast.showText(text: '网络环境不佳，请稍后尝试');
          throw Exception('WebSocket通信异常');
        }
      }
    } catch (e) {
      print('❌ WebSocket下载流程失败: $e');
      // 更新下载记录状态为失败
      if (downloadRecordId != null) {
        if (Get.isRegistered<DownloadController>()) {
          final downloadController = Get.find<DownloadController>();
          await _updateDownloadRecordStatus(
            downloadController: downloadController,
            recordId: downloadRecordId,
            status: DownloadStatus.failed,
            errorMessage: 'WebSocket连接失败',
          );
        }
      }
      BotToast.showText(text: '网络环境不佳，请稍后尝试');
    } finally {
      // 确保WebSocket连接被关闭
      wsChannel?.sink.close();
    }
  }

  /// 开始本地录像下载
  Future<void> _startLocalDownload({
    required String downloadUrl,
    required String deviceName,
    required String deviceId,
    required String channelId,
    required String channelName,
    required String startTime,
    required String endTime,
    required String duration,
    required String picUrl,
  }) async {
    try {
      print('🎯 开始本地录像下载...');

      // 检查并获取下载控制器
      if (!Get.isRegistered<DownloadController>()) {
        print('❌ DownloadController 未注册，尝试重新注册');
        Get.put(DownloadController(), permanent: true);
      }

      final downloadController = Get.find<DownloadController>();
      print('✅ 成功获取下载控制器');

      // 检查是否已存在相同的下载记录
      final existingRecords =
          downloadController.downloadRecords
              .where(
                (record) =>
                    record.videoUrl == downloadUrl &&
                    record.startTime == startTime &&
                    record.endTime == endTime,
              )
              .toList();

      if (existingRecords.isNotEmpty) {
        final existingRecord = existingRecords.first;
        if (existingRecord.status == DownloadStatus.waiting ||
            existingRecord.status == DownloadStatus.downloading) {
          BotToast.showText(text: '该视频正在下载中，请稍候');
          return;
        } else if (existingRecord.status == DownloadStatus.completed) {
          BotToast.showText(text: '下载完成，请前往我的下载进行查看');
          return;
        } else if (existingRecord.status == DownloadStatus.failed ||
            existingRecord.status == DownloadStatus.paused) {
          if (existingRecord.status == DownloadStatus.failed) {
            BotToast.showText(text: '检测到失败的下载，正在重新开始...');
          } else {
            BotToast.showText(text: '检测到暂停的下载，正在重新开始...');
          }
        }
      }

      // 开始下载
      print('🚀 调用startDownload方法...');
      await downloadController.startDownload(
        hlsUrl: downloadUrl,
        deviceName: deviceName,
        deviceId: deviceId,
        channelId: channelId,
        channelName: channelName,
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        picUrl: picUrl,
      );

      print('✅ 本地录像下载已启动');
      // BotToast.showText(text: '录像下载已开始，请在下载页面查看进度');

      // 强制更新UI
      update();
    } catch (e) {
      print('❌ 本地录像下载失败: $e');

      // 根据错误类型显示不同的提示
      final errorMessage = e.toString().toLowerCase();
      if (errorMessage.contains('handshake') || errorMessage.contains('ssl')) {
        BotToast.showText(text: '下载链接安全验证失败，请稍后重试');
      } else if (errorMessage.contains('timeout')) {
        BotToast.showText(text: '下载超时，请检查网络连接');
      } else if (errorMessage.contains('connection')) {
        BotToast.showText(text: '网络连接异常，请稍后重试');
      } else {
        BotToast.showText(text: '下载服务未初始化，请稍后重试');
      }
    }
  }

  /// 创建等待中的下载记录（在WebSocket连接开始时调用）
  Future<int?> _createWaitingDownloadRecord({
    required DownloadController downloadController,
    required String deviceName,
    required String deviceId,
    required String channelId,
    required String channelName,
    required String startTime,
    required String endTime,
    required String duration,
    required String picUrl,
  }) async {
    try {
      // 检查是否已存在相同的下载记录（基于设备ID、通道ID和时间）
      // 注意：这里不检查videoUrl，因为WebSocket流程中videoUrl是空的
      final existingRecords =
          downloadController.downloadRecords
              .where(
                (record) =>
                    record.startTime == startTime &&
                    record.endTime == endTime &&
                    record.deviceId == deviceId &&
                    record.channelId == channelId &&
                    (record.status == DownloadStatus.waiting ||
                        record.status == DownloadStatus.downloading ||
                        (record.videoUrl.isEmpty && record.status == DownloadStatus.waiting)),
              )
              .toList();

      if (existingRecords.isNotEmpty) {
        print('⚠️ 已存在相同的等待中下载记录，使用现有记录 ID: ${existingRecords.first.id}');
        return existingRecords.first.id;
      }

      // 获取用户ID
      final userId = await _getCurrentUserIdForDownload(downloadController);

      // 创建下载记录（videoUrl暂时为空，等待WebSocket返回）
      final record = DownloadRecord(
        userId: userId,
        deviceId: deviceId,
        deviceName: deviceName,
        channelId: channelId,
        channelName: channelName,
        videoUrl: '', // 暂时为空，等待WebSocket返回
        localPath: '',
        fileName: '',
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        fileSize: '0B',
        downloadedSize: '0B',
        progress: 0.0,
        speed: '0B/s',
        status: DownloadStatus.waiting,
        createdAt: DateTime.now(),
        picUrl: picUrl,
      );

      // 保存到数据库
      final databaseService = DownloadDatabaseService();
      final id = await databaseService.insertDownloadRecord(record);
      final savedRecord = record.copyWith(id: id);

      // 添加到列表
      downloadController.downloadRecords.insert(0, savedRecord);

      print('📝 创建等待中下载记录: ${savedRecord.deviceName} - ID: $id');

      // 强制更新UI
      downloadController.update();

      return id;
    } catch (e) {
      print('❌ 创建等待中下载记录失败: $e');
      return null;
    }
  }

  /// 获取当前用户ID（用于下载）
  Future<int> _getCurrentUserIdForDownload(
    DownloadController downloadController,
  ) async {
    try {
      final userService = Get.find<UserService>();
      final userId = userService.userId;
      if (userId != null) {
        return userId;
      }
      print('⚠️ 用户未登录，使用默认用户ID: 0');
      return 0;
    } catch (e) {
      print('❌ 获取用户ID失败: $e，使用默认用户ID: 0');
      return 0;
    }
  }

  /// 更新下载记录并开始下载
  Future<void> _updateAndStartDownload({
    required DownloadController downloadController,
    required int recordId,
    required String downloadUrl,
    required String deviceName,
    required String deviceId,
    required String channelId,
    required String channelName,
    required String startTime,
    required String endTime,
    required String duration,
    required String picUrl,
  }) async {
    try {
      // 查找记录
      final record = downloadController.downloadRecords.firstWhere(
        (r) => r.id == recordId,
      );

      // 更新记录的videoUrl和状态，重置进度信息
      final updatedRecord = record.copyWith(
        videoUrl: downloadUrl,
        downloadedSize: '0B',
        progress: 0.0,
        speed: '0B/s',
        status: DownloadStatus.waiting,
      );

      // 更新数据库
      final databaseService = DownloadDatabaseService();
      await databaseService.updateDownloadRecord(updatedRecord);

      // 更新本地列表
      final index = downloadController.downloadRecords.indexWhere(
        (r) => r.id == recordId,
      );
      if (index >= 0) {
        downloadController.downloadRecords[index] = updatedRecord;
      }

      // 强制更新UI
      downloadController.downloadRecords.refresh();
      downloadController.update();

      print('✅ 下载记录已更新，准备开始下载: ${updatedRecord.deviceName}');

      // 直接调用下载服务，使用现有记录ID，避免创建新记录
      await downloadController.startMp4DownloadWithRecordId(
        recordId: recordId,
        downloadUrl: downloadUrl,
      );

      print('✅ 下载已启动: ${updatedRecord.deviceName}');
    } catch (e) {
      print('❌ 更新并开始下载失败: $e');
      // 如果更新失败，尝试使用原来的方式创建新记录
      await _startLocalDownload(
        downloadUrl: downloadUrl,
        deviceName: deviceName,
        deviceId: deviceId,
        channelId: channelId,
        channelName: channelName,
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        picUrl: picUrl,
      );
    }
  }

  /// 更新WebSocket进度
  Future<void> _updateWebSocketProgress({
    required DownloadController downloadController,
    required int recordId,
    required int progress,
  }) async {
    try {
      final record = downloadController.downloadRecords.firstWhere(
        (r) => r.id == recordId,
        orElse: () => throw Exception('记录不存在'),
      );

      // 更新下载记录的进度信息，使用downloadedSize字段显示进度
      final updatedRecord = record.copyWith(
        downloadedSize: '正在连接服务器资源 $progress%',
        progress: progress / 100.0, // 转换为0-1之间的进度值
        status: DownloadStatus.waiting, // 保持等待状态，直到获取到下载链接
      );

      // 更新数据库
      final databaseService = DownloadDatabaseService();
      await databaseService.updateDownloadRecord(updatedRecord);

      // 更新本地列表
      final index = downloadController.downloadRecords.indexWhere(
        (r) => r.id == recordId,
      );
      if (index >= 0) {
        downloadController.downloadRecords[index] = updatedRecord;
      }

      // 强制更新UI
      downloadController.downloadRecords.refresh();
      downloadController.update();

      print('✅ WebSocket进度已更新: ${updatedRecord.deviceName} - $progress%');
    } catch (e) {
      print('❌ 更新WebSocket进度失败: $e');
    }
  }

  /// 更新下载记录状态
  Future<void> _updateDownloadRecordStatus({
    required DownloadController downloadController,
    required int recordId,
    required DownloadStatus status,
    String? errorMessage,
  }) async {
    try {
      final record = downloadController.downloadRecords.firstWhere(
        (r) => r.id == recordId,
        orElse: () => throw Exception('记录不存在'),
      );

      final updatedRecord = record.copyWith(
        status: status,
        errorMessage: errorMessage,
      );

      // 更新数据库
      final databaseService = DownloadDatabaseService();
      await databaseService.updateDownloadRecord(updatedRecord);

      // 更新本地列表
      final index = downloadController.downloadRecords.indexWhere(
        (r) => r.id == recordId,
      );
      if (index >= 0) {
        downloadController.downloadRecords[index] = updatedRecord;
      }

      // 强制更新UI
      downloadController.downloadRecords.refresh();
      downloadController.update();

      print('✅ 下载记录状态已更新: ${updatedRecord.deviceName} - $status');
    } catch (e) {
      print('❌ 更新下载记录状态失败: $e');
    }
  }

  /// 开始云端录像下载
  Future<void> _startCloudDownload({
    required String playUrl,
    required String deviceName,
    required String deviceId,
    required String channelId,
    required String channelName,
    required String startTime,
    required String endTime,
    required String duration,
    required String picUrl,
  }) async {
    try {
      print('🎯 开始云端录像下载...');

      // 检查并获取下载控制器
      if (!Get.isRegistered<DownloadController>()) {
        print('❌ DownloadController 未注册，尝试重新注册');
        Get.put(DownloadController(), permanent: true);
      }

      final downloadController = Get.find<DownloadController>();
      print('✅ 成功获取下载控制器');

      // 检查是否已存在相同的下载记录
      final existingRecords =
          downloadController.downloadRecords
              .where(
                (record) =>
                    record.videoUrl == playUrl &&
                    record.startTime == startTime &&
                    record.endTime == endTime,
              )
              .toList();

      if (existingRecords.isNotEmpty) {
        final existingRecord = existingRecords.first;
        if (existingRecord.status == DownloadStatus.waiting ||
            existingRecord.status == DownloadStatus.downloading) {
          BotToast.showText(text: '该视频正在下载中，请稍候');
          return;
        } else if (existingRecord.status == DownloadStatus.completed) {
          BotToast.showText(text: '下载完成，请前往我的下载进行查看');
          return;
        } else if (existingRecord.status == DownloadStatus.failed ||
            existingRecord.status == DownloadStatus.paused) {
          if (existingRecord.status == DownloadStatus.failed) {
            BotToast.showText(text: '检测到失败的下载，正在重新开始...');
          } else {
            BotToast.showText(text: '检测到暂停的下载，正在重新开始...');
          }
        }
      }

      // 开始下载
      print('🚀 调用startDownload方法...');
      await downloadController.startDownload(
        hlsUrl: playUrl,
        deviceName: deviceName,
        deviceId: deviceId,
        channelId: channelId,
        channelName: channelName,
        startTime: startTime,
        endTime: endTime,
        duration: duration,
        picUrl: picUrl,
      );

      print('✅ 云端录像下载已启动');
      // BotToast.showText(text: '录像下载已开始，请在下载页面查看进度');

      // 强制更新UI
      update();
    } catch (e) {
      print('❌ 云端录像下载失败: $e');

      // 根据错误类型显示不同的提示
      final errorMessage = e.toString().toLowerCase();
      if (errorMessage.contains('handshake') || errorMessage.contains('ssl')) {
        BotToast.showText(text: '下载链接安全验证失败，请稍后重试');
      } else if (errorMessage.contains('timeout')) {
        BotToast.showText(text: '下载超时，请检查网络连接');
      } else if (errorMessage.contains('connection')) {
        BotToast.showText(text: '网络连接异常，请稍后重试');
      } else {
        BotToast.showText(text: '下载服务未初始化，请稍后重试');
      }
    }
  }

  /// 显示下载确认弹窗
  Future<bool> _showDownloadConfirmDialog({
    required String deviceName,
    required String startTime,
    required String endTime,
    required String duration,
  }) async {
    return await Get.dialog<bool>(
          AlertDialog(
            title: Text('确认下载'),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('设备: $deviceName'),
                SizedBox(height: 8),
                Text('时间: $startTime - $endTime'),
                SizedBox(height: 8),
                Text('时长: $duration'),
              ],
            ),
            actions: [
              TextButton(
                onPressed: () => Get.back(result: false),
                child: Text('取消'),
              ),
              ElevatedButton(
                onPressed: () => Get.back(result: true),
                child: Text('确认下载'),
              ),
            ],
          ),
        ) ??
        false;
  }
}
